mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2026-01-08 12:52:11 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4565b8529 | ||
|
|
041c64ff65 | ||
|
|
b0bdb7b445 | ||
|
|
99a7564648 | ||
|
|
dbb3f4c83f | ||
|
|
edd40c078f | ||
|
|
d3b637a0c8 | ||
|
|
d7e3c62deb | ||
|
|
7b319268fe | ||
|
|
41883f7798 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -18,6 +18,10 @@
|
||||
/utils
|
||||
test.py
|
||||
RES.txt
|
||||
/MSCT_Packer.py
|
||||
/Packer/*.MPK
|
||||
/Packer/checksum.txt
|
||||
/bgArrayLib
|
||||
|
||||
# Byte-compiled / optimized
|
||||
__pycache__/
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
Musicreater(音·创)
|
||||
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
|
||||
__version__ = "1.6.2"
|
||||
__vername__ = "新的转换算法测试,更好的声音适配"
|
||||
__version__ = "1.7.4"
|
||||
__vername__ = "部分音色更新"
|
||||
__author__ = (
|
||||
("金羿", "Eilles Wan"),
|
||||
("诸葛亮与八卦阵", "bgArray"),
|
||||
@@ -31,7 +31,15 @@ __all__ = [
|
||||
# 附加类
|
||||
"SingleNote",
|
||||
"SingleCommand",
|
||||
"SingleNoteBox",
|
||||
# "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 *
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
from typing import Dict, List, Tuple
|
||||
from .types import Dict, List, Tuple, MidiInstrumentTableType, MidiNoteNameTableType
|
||||
|
||||
x = "x"
|
||||
"""
|
||||
@@ -33,13 +33,8 @@ z = "z"
|
||||
z
|
||||
"""
|
||||
|
||||
DEFAULT_PROGRESSBAR_STYLE = (
|
||||
r"▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]",
|
||||
("§e=§r", "§7=§r"),
|
||||
)
|
||||
"""
|
||||
默认的进度条样式组
|
||||
"""
|
||||
|
||||
# Midi用对照表
|
||||
|
||||
MIDI_PITCH_NAME_TABLE: Dict[int, str] = {
|
||||
0: "C",
|
||||
@@ -171,12 +166,468 @@ MIDI_PITCH_NAME_TABLE: Dict[int, str] = {
|
||||
126: "F#",
|
||||
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.snare", -1),
|
||||
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 “偷吃” 带来的高准确率音效对照表
|
||||
# 包括乐音乐器对照和打击乐器对照
|
||||
|
||||
PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
MM_TOUCH_PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
0: ("note.harp", 6),
|
||||
1: ("note.harp", 6),
|
||||
2: ("note.pling", 6),
|
||||
@@ -224,7 +675,7 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
44: ("note.flute", 5),
|
||||
45: ("note.iron_xylophone", 6),
|
||||
46: ("note.harp", 6),
|
||||
47: ("note.snare", 7),
|
||||
47: ("note.snare", -1),
|
||||
48: ("note.flute", 5),
|
||||
49: ("note.flute", 5),
|
||||
50: ("note.flute", 5),
|
||||
@@ -232,7 +683,7 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
52: ("note.didgeridoo", 5),
|
||||
53: ("note.flute", 5), # 合唱“啊”音
|
||||
54: ("note.flute", 5), # 人声“嘟”音
|
||||
55: ("mob.zombie.wood", 7), # 合成人声
|
||||
55: ("mob.zombie.wood", -1), # 合成人声
|
||||
56: ("note.flute", 5),
|
||||
57: ("note.flute", 5),
|
||||
58: ("note.flute", 5),
|
||||
@@ -292,136 +743,100 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
112: ("note.bell", 4),
|
||||
113: ("note.xylophone", 4),
|
||||
114: ("note.flute", 5),
|
||||
115: ("note.hat", 7), # 打击乐器无音域
|
||||
116: ("note.snare", 7), # 打击乐器无音域
|
||||
117: ("note.snare", 7), # 打击乐器无音域
|
||||
118: ("note.bd", 7), # 打击乐器无音域
|
||||
119: ("firework.blast", 7), # 打击乐器无音域
|
||||
115: ("note.hat", -1), # 打击乐器无音域
|
||||
116: ("note.snare", -1), # 打击乐器无音域
|
||||
117: ("note.snare", -1), # 打击乐器无音域
|
||||
118: ("note.bd", -1), # 打击乐器无音域
|
||||
119: ("firework.blast", -1), # 打击乐器无音域
|
||||
120: ("note.guitar", 7), # 吉他还把杂音
|
||||
121: ("note.harp", 6), # 呼吸声
|
||||
122: ("note.harp", 6), # 海浪声
|
||||
123: ("note.harp", 6), # 鸟鸣
|
||||
124: ("note.bit", 6),
|
||||
125: ("note.hat", 7), # 直升机
|
||||
126: ("firework.twinkle", 7), # 打击乐器无音域
|
||||
127: ("mob.zombie.wood", 7), # 打击乐器无音域
|
||||
125: ("note.hat", -1), # 直升机
|
||||
126: ("firework.twinkle", -1), # 打击乐器无音域
|
||||
127: ("mob.zombie.wood", -1), # 打击乐器无音域
|
||||
}
|
||||
"""“偷吃”乐音乐器对照表"""
|
||||
|
||||
PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
34: ("note.hat", 7),
|
||||
35: ("note.bd", 7),
|
||||
36: ("note.bd", 7),
|
||||
37: ("note.snare", 7),
|
||||
38: ("note.snare", 7),
|
||||
MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
|
||||
34: ("note.hat", -1),
|
||||
35: ("note.bd", -1),
|
||||
36: ("note.bd", -1),
|
||||
37: ("note.snare", -1),
|
||||
38: ("note.snare", -1),
|
||||
39: ("fire.ignite", 7),
|
||||
40: ("note.snare", 7),
|
||||
41: ("note.hat", 7),
|
||||
42: ("note.hat", 7),
|
||||
43: ("firework.blast", 7),
|
||||
44: ("note.hat", 7),
|
||||
45: ("note.snare", 4),
|
||||
46: ("note.snare", 7),
|
||||
47: ("note.snare", 7),
|
||||
40: ("note.snare", -1),
|
||||
41: ("note.hat", -1),
|
||||
42: ("note.hat", -1),
|
||||
43: ("firework.blast", -1),
|
||||
44: ("note.hat", -1),
|
||||
45: ("note.snare", -1),
|
||||
46: ("note.snare", -1),
|
||||
47: ("note.snare", -1),
|
||||
48: ("note.bell", 4),
|
||||
49: ("note.hat", 7),
|
||||
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", 7),
|
||||
57: ("note.hat", 7),
|
||||
56: ("note.snare", -1),
|
||||
57: ("note.hat", -1),
|
||||
58: ("note.chime", 4),
|
||||
59: ("note.iron_xylophone", 6),
|
||||
60: ("note.bd", 7),
|
||||
61: ("note.bd", 7),
|
||||
60: ("note.bd", -1),
|
||||
61: ("note.bd", -1),
|
||||
62: ("note.xylophone", 4),
|
||||
63: ("note.xylophone", 4),
|
||||
64: ("note.xylophone", 4),
|
||||
65: ("note.hat", 7),
|
||||
65: ("note.hat", -1),
|
||||
66: ("note.bell", 4),
|
||||
67: ("note.bell", 4),
|
||||
68: ("note.hat", 7),
|
||||
69: ("note.hat", 7),
|
||||
70: ("note.flute", 5),
|
||||
68: ("note.hat", -1),
|
||||
69: ("note.hat", -1),
|
||||
70: ("note.snare", -1),
|
||||
71: ("note.flute", 5),
|
||||
72: ("note.hat", 7),
|
||||
73: ("note.hat", 7),
|
||||
72: ("note.hat", -1),
|
||||
73: ("note.hat", -1),
|
||||
74: ("note.xylophone", 4),
|
||||
75: ("note.hat", 7),
|
||||
76: ("note.hat", 7),
|
||||
75: ("note.hat", -1),
|
||||
76: ("note.hat", -1),
|
||||
77: ("note.xylophone", 4),
|
||||
78: ("note.xylophone", 4),
|
||||
79: ("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 = {
|
||||
0.5: 0,
|
||||
0.53: 1,
|
||||
0.56: 2,
|
||||
0.6: 3,
|
||||
0.63: 4,
|
||||
0.67: 5,
|
||||
0.7: 6,
|
||||
0.75: 7,
|
||||
0.8: 8,
|
||||
0.84: 9,
|
||||
0.9: 10,
|
||||
0.94: 11,
|
||||
1.0: 12,
|
||||
1.05: 13,
|
||||
1.12: 14,
|
||||
1.2: 15,
|
||||
1.25: 16,
|
||||
1.33: 17,
|
||||
1.4: 18,
|
||||
1.5: 19,
|
||||
1.6: 20,
|
||||
1.7: 21,
|
||||
1.8: 22,
|
||||
1.9: 23,
|
||||
2.0: 24,
|
||||
}
|
||||
"""音高对照表\n
|
||||
MC音高:音符盒音调"""
|
||||
# height2note = {
|
||||
# 0.5: 0,
|
||||
# 0.53: 1,
|
||||
# 0.56: 2,
|
||||
# 0.6: 3,
|
||||
# 0.63: 4,
|
||||
# 0.67: 5,
|
||||
# 0.7: 6,
|
||||
# 0.75: 7,
|
||||
# 0.8: 8,
|
||||
# 0.84: 9,
|
||||
# 0.9: 10,
|
||||
# 0.94: 11,
|
||||
# 1.0: 12,
|
||||
# 1.05: 13,
|
||||
# 1.12: 14,
|
||||
# 1.2: 15,
|
||||
# 1.25: 16,
|
||||
# 1.33: 17,
|
||||
# 1.4: 18,
|
||||
# 1.5: 19,
|
||||
# 1.6: 20,
|
||||
# 1.7: 21,
|
||||
# 1.8: 22,
|
||||
# 1.9: 23,
|
||||
# 2.0: 24,
|
||||
# }
|
||||
# """音高对照表\n
|
||||
# MC音高:音符盒音调"""
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
import random
|
||||
|
||||
from .constants import INSTRUMENT_BLOCKS_TABLE
|
||||
from .exceptions import *
|
||||
from .main import MidiConvert
|
||||
from .subclass 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):
|
||||
@@ -34,30 +36,6 @@ class FutureMidiConvertRSNB(MidiConvert):
|
||||
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):
|
||||
"""
|
||||
@@ -101,6 +79,7 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
lastime=int(_note.duration / totalCount),
|
||||
track_number=_note.track_no,
|
||||
is_percussion=_note.percussive,
|
||||
extra_information=_note.extra_info,
|
||||
)
|
||||
# (
|
||||
# _note.start_time + _i * _apply_time_division,
|
||||
@@ -145,8 +124,21 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
# 此处 我们把通道视为音轨
|
||||
for channel in self.to_music_note_channels().values():
|
||||
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:
|
||||
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:
|
||||
notes_list.append(note)
|
||||
|
||||
@@ -166,12 +158,12 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
self.music_command_list.append(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ note.to_command(max_volume),
|
||||
+ r"playsound {} @s ^ ^ ^{} {} {}".format(*note.extra_info),
|
||||
tick_delay=tickdelay,
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(delaytime_now),
|
||||
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(
|
||||
self,
|
||||
@@ -237,9 +305,13 @@ class FutureMidiConvertM5(MidiConvert):
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
soundID, _X = (
|
||||
self.perc_inst_to_soundID_withX(msg[1])
|
||||
inst_to_sould_with_deviation(
|
||||
msg[1], MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE
|
||||
)
|
||||
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)
|
||||
|
||||
@@ -22,24 +22,24 @@
|
||||
Musicreater (音·创)
|
||||
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 ../License.md
|
||||
Terms & Conditions: ../License.md
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# ============================
|
||||
|
||||
|
||||
|
||||
|
||||
import mido
|
||||
|
||||
|
||||
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.note = pitch
|
||||
self.velocity = velocity
|
||||
@@ -49,19 +49,39 @@ class NoteMessage:
|
||||
|
||||
def mt2gt(mt, tpb_a, bpm_a):
|
||||
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())
|
||||
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:
|
||||
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())
|
||||
print((self.startTime * self.tempo) / (midi.ticks_per_beat * 50000))
|
||||
|
||||
def __str__(self):
|
||||
return "noteMessage channel=" + 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)
|
||||
return (
|
||||
"noteMessage channel="
|
||||
+ 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):
|
||||
@@ -75,7 +95,7 @@ def load(mid: mido.MidiFile):
|
||||
for msg in track:
|
||||
# print(msg)
|
||||
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
|
||||
elif msg.type == "note_off":
|
||||
type_[0] = True
|
||||
@@ -105,13 +125,13 @@ def load(mid: mido.MidiFile):
|
||||
print(ticks)
|
||||
if msg.is_meta is True and msg.type == "set_tempo":
|
||||
recent_change_bpm = bpm
|
||||
bpm = 60000000 / msg.tempo
|
||||
bpm = 60000000 / msg.tempo
|
||||
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])
|
||||
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:
|
||||
index = 0
|
||||
if u[1] == msg.note:
|
||||
@@ -121,13 +141,31 @@ def load(mid: mido.MidiFile):
|
||||
index += 1
|
||||
print(lastTick)
|
||||
if is_change_bpm and recent_change_bpm != 0:
|
||||
trackS.append(NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick,
|
||||
mid, recent_change_bpm, bpm))
|
||||
trackS.append(
|
||||
NoteMessage(
|
||||
msg.channel,
|
||||
msg.note,
|
||||
lastMessage.velocity,
|
||||
lastTick,
|
||||
ticks - lastTick,
|
||||
mid,
|
||||
recent_change_bpm,
|
||||
bpm,
|
||||
)
|
||||
)
|
||||
is_change_bpm = False
|
||||
else:
|
||||
trackS.append(
|
||||
NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick,
|
||||
mid, bpm))
|
||||
NoteMessage(
|
||||
msg.channel,
|
||||
msg.note,
|
||||
lastMessage.velocity,
|
||||
lastTick,
|
||||
ticks - lastTick,
|
||||
mid,
|
||||
bpm,
|
||||
)
|
||||
)
|
||||
# print(noteOn)
|
||||
# print(index)
|
||||
try:
|
||||
@@ -139,20 +177,19 @@ def load(mid: mido.MidiFile):
|
||||
print(j)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
load(mido.MidiFile("test.mid"))
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================
|
||||
from typing import Literal
|
||||
from ..constants import x,y,z
|
||||
from ..constants import x, y, z
|
||||
|
||||
|
||||
# 不要用 没写完
|
||||
def delay_to_note_blocks(
|
||||
baseblock: str = "stone",
|
||||
position_forward: Literal['x','y','z'] = z,
|
||||
baseblock: str = "stone",
|
||||
position_forward: Literal["x", "y", "z"] = z,
|
||||
):
|
||||
"""传入音符,生成以音符盒存储的红石音乐
|
||||
:param:
|
||||
@@ -169,8 +206,7 @@ def delay_to_note_blocks(
|
||||
|
||||
log = print
|
||||
|
||||
startpos = [0,0,0]
|
||||
|
||||
startpos = [0, 0, 0]
|
||||
|
||||
# 1拍 x 2.5 rt
|
||||
for i in notes:
|
||||
@@ -180,7 +216,10 @@ def delay_to_note_blocks(
|
||||
[startpos[0], startpos[1] + 1, startpos[2]],
|
||||
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
|
||||
except ValueError:
|
||||
log("无法放置音符:" + str(i) + "于" + str(startpos))
|
||||
@@ -222,4 +261,4 @@ def delay_to_note_blocks(
|
||||
struct.set_block(Block("universal_minecraft", baseblock), startpos)
|
||||
startpos[0] += posadder[0]
|
||||
startpos[1] += posadder[1]
|
||||
startpos[2] += posadder[2]
|
||||
startpos[2] += posadder[2]
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
Musicreater (音·创)
|
||||
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -28,6 +28,8 @@ Terms & Conditions: License.md in the root directory
|
||||
import math
|
||||
import os
|
||||
|
||||
import mido
|
||||
|
||||
from .constants import *
|
||||
from .exceptions 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)
|
||||
class MidiConvert:
|
||||
"""
|
||||
@@ -77,6 +85,15 @@ class MidiConvert:
|
||||
midi: VoidMido
|
||||
"""MidiFile对象"""
|
||||
|
||||
pitched_note_reference_table: MidiInstrumentTableType
|
||||
"""乐音乐器Midi-MC对照表"""
|
||||
|
||||
percussion_note_referrence_table: MidiInstrumentTableType
|
||||
"""打击乐器Midi-MC对照表"""
|
||||
|
||||
volume_processing_function: FittingFunctionType
|
||||
"""音量处理函数"""
|
||||
|
||||
midi_music_name: str
|
||||
"""Midi乐曲名"""
|
||||
|
||||
@@ -103,6 +120,9 @@ class MidiConvert:
|
||||
midi_obj: VoidMido,
|
||||
midi_name: str,
|
||||
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对象转换为我的世界结构或者包
|
||||
@@ -115,6 +135,10 @@ class MidiConvert:
|
||||
此音乐之名
|
||||
enable_old_exe_format: bool
|
||||
是否启用旧版(≤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
|
||||
@@ -129,6 +153,10 @@ class MidiConvert:
|
||||
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.channels = {}
|
||||
self.music_tick_num = 0
|
||||
@@ -138,6 +166,9 @@ class MidiConvert:
|
||||
cls,
|
||||
midi_file_path: str,
|
||||
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文件读入
|
||||
@@ -148,6 +179,10 @@ class MidiConvert:
|
||||
midi文件地址
|
||||
enable_old_exe_format: bool
|
||||
是否启用旧版(≤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(
|
||||
@@ -160,6 +195,9 @@ class MidiConvert:
|
||||
mido.MidiFile(midi_file_path, clip=True),
|
||||
midi_music_name,
|
||||
old_exe_format,
|
||||
pitched_note_table,
|
||||
percussion_note_table,
|
||||
vol_processing_func,
|
||||
)
|
||||
except (ValueError, TypeError) as E:
|
||||
raise MidiDestroyedError(f"文件{midi_file_path}损坏:{E}")
|
||||
@@ -173,7 +211,7 @@ class MidiConvert:
|
||||
self,
|
||||
max_score: int,
|
||||
scoreboard_name: str,
|
||||
progressbar_style: tuple = DEFAULT_PROGRESSBAR_STYLE,
|
||||
progressbar_style: ProgressBarStyle = DEFAULT_PROGRESSBAR_STYLE,
|
||||
) -> List[SingleCommand]:
|
||||
"""
|
||||
生成进度条
|
||||
@@ -193,7 +231,7 @@ class MidiConvert:
|
||||
-------
|
||||
list[SingleCommand,]
|
||||
"""
|
||||
pgs_style = progressbar_style[0]
|
||||
pgs_style = progressbar_style.base_style
|
||||
"""用于被替换的进度条原始样式"""
|
||||
|
||||
"""
|
||||
@@ -222,8 +260,10 @@ class MidiConvert:
|
||||
if r"%%%" in pgs_style:
|
||||
result.append(
|
||||
SingleCommand(
|
||||
'scoreboard objectives add {}PercT dummy "百分比计算"'.format(sbn_pc),
|
||||
annotation="新增临时计算用计分板(百分比)",
|
||||
'scoreboard objectives add {}PercT dummy "百分比计算"'.format(
|
||||
sbn_pc
|
||||
),
|
||||
annotation="新增临时百分比变量",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -234,7 +274,7 @@ class MidiConvert:
|
||||
+ "scoreboard players set MaxScore {} {}".format(
|
||||
scoreboard_name, max_score
|
||||
),
|
||||
annotation="设定此音乐最大计分",
|
||||
annotation="设定音乐最大延迟分数",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -254,7 +294,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} = @s {}".format(
|
||||
sbn_pc + "PercT", scoreboard_name
|
||||
),
|
||||
annotation="为临时变量赋值",
|
||||
annotation="赋值临时百分比",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -265,7 +305,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} *= n100 {}".format(
|
||||
sbn_pc + "PercT", scoreboard_name
|
||||
),
|
||||
annotation="改变临时变量的单位为百分比(扩大精度)",
|
||||
annotation="转换临时百分比之单位至%(扩大精度)",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -276,7 +316,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} /= MaxScore {}".format(
|
||||
sbn_pc + "PercT", scoreboard_name
|
||||
),
|
||||
annotation="使用临时变量计算百分比",
|
||||
annotation="计算百分比",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -287,14 +327,18 @@ class MidiConvert:
|
||||
if r"%%t" in pgs_style:
|
||||
result.append(
|
||||
SingleCommand(
|
||||
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(sbn_pc),
|
||||
annotation="新增临时计算计分板(分)",
|
||||
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(
|
||||
sbn_pc
|
||||
),
|
||||
annotation="新增临时分变量",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
SingleCommand(
|
||||
'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(sbn_pc),
|
||||
annotation="新增临时计算计分板(秒)",
|
||||
'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(
|
||||
sbn_pc
|
||||
),
|
||||
annotation="新增临时秒变量",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -324,7 +368,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} = @s {}".format(
|
||||
sbn_pc + "TMinT", scoreboard_name
|
||||
),
|
||||
annotation="为临时变量(分)赋值",
|
||||
annotation="赋值临时分",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -335,7 +379,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} /= n20 {}".format(
|
||||
sbn_pc + "TMinT", scoreboard_name
|
||||
),
|
||||
annotation="将临时变量转换单位为秒(缩减精度)",
|
||||
annotation="转换临时分之单位为秒(缩减精度)",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
@@ -346,7 +390,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} = @s {}".format(
|
||||
sbn_pc + "TSecT", sbn_pc + "TMinT"
|
||||
),
|
||||
annotation="为临时变量(秒)赋值",
|
||||
annotation="赋值临时秒",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -358,7 +402,7 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} /= n60 {}".format(
|
||||
sbn_pc + "TMinT", scoreboard_name
|
||||
),
|
||||
annotation="将临时变量(分)转换单位为分(缩减精度)",
|
||||
annotation="转换临时分之单位为分(缩减精度)",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -370,42 +414,35 @@ class MidiConvert:
|
||||
+ "scoreboard players operation @s {} %= n60 {}".format(
|
||||
sbn_pc + "TSecT", scoreboard_name
|
||||
),
|
||||
annotation="将临时变量(秒)确定下来(框定精度区间)",
|
||||
annotation="确定临时秒(框定精度区间)",
|
||||
)
|
||||
)
|
||||
|
||||
for i in range(pgs_style.count("_")):
|
||||
npg_stl = (
|
||||
pgs_style.replace("_", progressbar_style[1][0], i + 1)
|
||||
.replace("_", progressbar_style[1][1])
|
||||
pgs_style.replace("_", progressbar_style.played_style, i + 1)
|
||||
.replace("_", progressbar_style.to_play_style)
|
||||
.replace(r"%%N", self.midi_music_name)
|
||||
if r"%%N" in pgs_style
|
||||
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(
|
||||
.replace(
|
||||
r"%%s",
|
||||
'"},{"score":{"name":"*","objective":"'
|
||||
+ scoreboard_name
|
||||
+ '"}},{"text":"',
|
||||
)
|
||||
if r"%%%" in npg_stl:
|
||||
npg_stl = npg_stl.replace(
|
||||
.replace(
|
||||
r"%%%",
|
||||
r'"},{"score":{"name":"*","objective":"'
|
||||
+ sbn_pc
|
||||
+ r'PercT"}},{"text":"%',
|
||||
)
|
||||
if r"%%t" in npg_stl:
|
||||
npg_stl = npg_stl.replace(
|
||||
.replace(
|
||||
r"%%t",
|
||||
r'"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},'
|
||||
r'{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace(
|
||||
r"{-}", sbn_pc
|
||||
),
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(
|
||||
@@ -425,20 +462,20 @@ class MidiConvert:
|
||||
result.append(
|
||||
SingleCommand(
|
||||
"scoreboard objectives remove {}PercT".format(sbn_pc),
|
||||
annotation="移除临时计算计分板(百分比)",
|
||||
annotation="移除临时百分比变量",
|
||||
)
|
||||
)
|
||||
if r"%%t" in pgs_style:
|
||||
result.append(
|
||||
SingleCommand(
|
||||
"scoreboard objectives remove {}TMinT".format(sbn_pc),
|
||||
annotation="移除临时计算计分板(分)",
|
||||
annotation="移除临时分变量",
|
||||
)
|
||||
)
|
||||
result.append(
|
||||
SingleCommand(
|
||||
"scoreboard objectives remove {}TSecT".format(sbn_pc),
|
||||
annotation="移除临时计算计分板(秒)",
|
||||
annotation="移除临时秒变量",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -447,6 +484,7 @@ class MidiConvert:
|
||||
|
||||
def to_music_note_channels(
|
||||
self,
|
||||
default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
|
||||
ignore_mismatch_error: bool = True,
|
||||
) -> NoteChannelType:
|
||||
"""
|
||||
@@ -465,7 +503,7 @@ class MidiConvert:
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: NoteChannelType = empty_midi_channels(staff=[])
|
||||
tempo = mido.midifiles.midifiles.DEFAULT_TEMPO
|
||||
tempo = default_tempo_value
|
||||
|
||||
# 我们来用通道统计音乐信息
|
||||
# 但是是用分轨的思路的
|
||||
@@ -557,7 +595,9 @@ class MidiConvert:
|
||||
)
|
||||
else:
|
||||
raise NoteOnOffMismatchError(
|
||||
"当前的MIDI很可能有损坏之嫌……", msg, "无法在上文中找到与之匹配的音符开音消息。"
|
||||
"当前的MIDI很可能有损坏之嫌……",
|
||||
msg,
|
||||
"无法在上文中找到与之匹配的音符开音消息。",
|
||||
)
|
||||
|
||||
"""整合后的音乐通道格式
|
||||
@@ -624,20 +664,55 @@ class MidiConvert:
|
||||
score_now = round(note.start_time / float(speed) / 50)
|
||||
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(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(
|
||||
"@a[scores=({}={})]".format(scoreboard_name, score_now)
|
||||
.replace("(", r"{")
|
||||
.replace(")", r"}")
|
||||
)
|
||||
+ note.to_command(
|
||||
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
|
||||
(
|
||||
self.execute_cmd_head.format(
|
||||
"@a[scores=({}={})]".format(scoreboard_name, score_now)
|
||||
.replace("(", r"{")
|
||||
.replace(")", r"}")
|
||||
)
|
||||
+ (
|
||||
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(score_now),
|
||||
max_volume * 100,
|
||||
"{}:{}".format(note.mc_sound_ID, note.mc_pitch),
|
||||
annotation=(
|
||||
"在{}播放{}%的{}噪音".format(
|
||||
mctick2timestr(score_now),
|
||||
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)
|
||||
|
||||
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(
|
||||
self,
|
||||
@@ -697,19 +772,55 @@ class MidiConvert:
|
||||
else:
|
||||
max_multi = max(max_multi, multi)
|
||||
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(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ note.to_command(
|
||||
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
|
||||
command=(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ (
|
||||
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,
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(delaytime_now),
|
||||
max_volume * 100,
|
||||
"{}:{}".format(note.mc_sound_ID, note.mc_pitch),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
delaytime_previous = delaytime_now
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
存放非音·创本体的附加内容(插件?)
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -15,8 +15,57 @@ Terms & Conditions: License.md in the root directory
|
||||
|
||||
|
||||
__all__ = [
|
||||
# 通用
|
||||
"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"))
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
用以生成附加包的附加功能
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -102,15 +102,17 @@ def to_addon_pack_in_score(
|
||||
+ scoreboard_name
|
||||
+ " 1\n",
|
||||
(
|
||||
"scoreboard players reset @a[scores={"
|
||||
+ scoreboard_name
|
||||
+ "="
|
||||
+ str(maxscore + 20)
|
||||
+ "..}]"
|
||||
+ f" {scoreboard_name}\n"
|
||||
)
|
||||
if auto_reset
|
||||
else "",
|
||||
(
|
||||
"scoreboard players reset @a[scores={"
|
||||
+ scoreboard_name
|
||||
+ "="
|
||||
+ str(maxscore + 20)
|
||||
+ "..}]"
|
||||
+ f" {scoreboard_name}\n"
|
||||
)
|
||||
if auto_reset
|
||||
else ""
|
||||
),
|
||||
f"function mscplay/progressShow\n" if data_cfg.progressbar_style else "",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -21,7 +21,7 @@ from ..constants import x, y, z
|
||||
from ..subclass import SingleCommand
|
||||
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"],
|
||||
"y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"],
|
||||
"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:
|
||||
return b""
|
||||
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(
|
||||
[
|
||||
1 if i else 0
|
||||
for i in (
|
||||
value != -1,
|
||||
value < -1 or value > 1,
|
||||
value < -128 or value > 127,
|
||||
value < -32768 or value > 32767,
|
||||
)
|
||||
value != -1,
|
||||
value < -1 or value > 1,
|
||||
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
|
||||
)
|
||||
|
||||
@@ -150,18 +147,20 @@ def commands_to_BDX_bytes(
|
||||
for command in commands_list:
|
||||
_bytes += form_command_block_in_BDX_bytes(
|
||||
command.command_text,
|
||||
(1 if y_forward else 0)
|
||||
if (
|
||||
((now_y != 0) and (not y_forward))
|
||||
or (y_forward and (now_y != (max_height - 1)))
|
||||
)
|
||||
else (
|
||||
(3 if z_forward else 2)
|
||||
(
|
||||
(1 if y_forward else 0)
|
||||
if (
|
||||
((now_z != 0) and (not z_forward))
|
||||
or (z_forward and (now_z != _sideLength - 1))
|
||||
((now_y != 0) and (not y_forward))
|
||||
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,
|
||||
condition=command.conditional,
|
||||
@@ -196,13 +195,13 @@ def commands_to_BDX_bytes(
|
||||
):
|
||||
now_z -= 1 if z_forward else -1
|
||||
z_forward = not z_forward
|
||||
_bytes += bdx_key[x][1]
|
||||
_bytes += BDX_MOVE_KEY[x][1]
|
||||
now_x += 1
|
||||
else:
|
||||
_bytes += bdx_key[z][int(z_forward)]
|
||||
_bytes += BDX_MOVE_KEY[z][int(z_forward)]
|
||||
|
||||
else:
|
||||
_bytes += bdx_key[y][int(y_forward)]
|
||||
_bytes += BDX_MOVE_KEY[y][int(y_forward)]
|
||||
|
||||
return (
|
||||
_bytes,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
用以生成BDX结构文件的附加功能
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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 typing import Literal, Tuple, Union
|
||||
|
||||
from ..constants import DEFAULT_PROGRESSBAR_STYLE
|
||||
from ..subclass import DEFAULT_PROGRESSBAR_STYLE, ProgressBarStyle
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
@@ -34,8 +34,8 @@ class ConvertConfig:
|
||||
speed_multiplier: float
|
||||
"""速度倍率"""
|
||||
|
||||
progressbar_style: Union[Tuple[str, Tuple[str, str]], Literal[None]]
|
||||
"""进度条样式组"""
|
||||
progressbar_style: Union[ProgressBarStyle, None]
|
||||
"""进度条样式"""
|
||||
|
||||
dist_path: str
|
||||
"""输出目录"""
|
||||
@@ -45,7 +45,8 @@ class ConvertConfig:
|
||||
output_path: str,
|
||||
volume: 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可读格式
|
||||
@@ -77,10 +78,29 @@ class ConvertConfig:
|
||||
# 改这一段没🐎
|
||||
if progressbar is True:
|
||||
self.progressbar_style = DEFAULT_PROGRESSBAR_STYLE
|
||||
"""进度条样式组"""
|
||||
else:
|
||||
"""进度条样式"""
|
||||
return
|
||||
elif isinstance(progressbar, ProgressBarStyle):
|
||||
self.progressbar_style = progressbar
|
||||
"""进度条样式组"""
|
||||
else:
|
||||
self.progressbar_style = None
|
||||
"""进度条样式组"""
|
||||
"""进度条样式"""
|
||||
return
|
||||
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
|
||||
"""进度条样式组"""
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
用以生成单个mcstructure文件的附加功能
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -17,7 +17,8 @@ Terms & Conditions: License.md in the root directory
|
||||
__all__ = [
|
||||
"to_mcstructure_file_in_delay",
|
||||
"to_mcstructure_file_in_repeater",
|
||||
"to_mcstructure_file_in_score",
|
||||
]
|
||||
__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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -14,9 +14,10 @@ Terms & Conditions: License.md in the root directory
|
||||
import os
|
||||
from typing import Literal
|
||||
|
||||
from ...exceptions import CommandFormatError
|
||||
# from ...exceptions import CommandFormatError
|
||||
from ...main import MidiConvert
|
||||
from ..main import ConvertConfig
|
||||
from ...subclass import SingleCommand
|
||||
from ..mcstructure import (
|
||||
COMPABILITY_VERSION_117,
|
||||
COMPABILITY_VERSION_119,
|
||||
@@ -47,7 +48,7 @@ def to_mcstructure_file_in_delay(
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple[tuple[int,]结构大小, int音乐总延迟]
|
||||
tuple[tuple[int,int,int]结构大小, int音乐总延迟]
|
||||
"""
|
||||
|
||||
compability_ver = (
|
||||
@@ -80,6 +81,78 @@ def to_mcstructure_file_in_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(
|
||||
midi_cvt: MidiConvert,
|
||||
data_cfg: ConvertConfig,
|
||||
@@ -105,7 +178,7 @@ def to_mcstructure_file_in_repeater(
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple[tuple[int,]结构大小, int音乐总延迟]
|
||||
tuple[tuple[int,int,int]结构大小, int音乐总延迟]
|
||||
"""
|
||||
|
||||
compability_ver = (
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -189,9 +189,11 @@ def form_command_block_in_NBT_struct(
|
||||
|
||||
return Block(
|
||||
"minecraft",
|
||||
"command_block"
|
||||
if impluse == 0
|
||||
else ("repeating_command_block" if impluse == 1 else "chain_command_block"),
|
||||
(
|
||||
"command_block"
|
||||
if impluse == 0
|
||||
else ("repeating_command_block" if impluse == 1 else "chain_command_block")
|
||||
),
|
||||
states={"conditional_bit": condition, "facing_direction": particularValue},
|
||||
extra_data={
|
||||
"block_entity_data": {
|
||||
@@ -257,18 +259,20 @@ def commands_to_structure(
|
||||
form_command_block_in_NBT_struct(
|
||||
command=command.command_text,
|
||||
coordinate=coordinate,
|
||||
particularValue=(1 if y_forward else 0)
|
||||
if (
|
||||
((now_y != 0) and (not y_forward))
|
||||
or (y_forward and (now_y != (max_height - 1)))
|
||||
)
|
||||
else (
|
||||
(3 if z_forward else 2)
|
||||
particularValue=(
|
||||
(1 if y_forward else 0)
|
||||
if (
|
||||
((now_z != 0) and (not z_forward))
|
||||
or (z_forward and (now_z != _sideLength - 1))
|
||||
((now_y != 0) and (not y_forward))
|
||||
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,
|
||||
condition=False,
|
||||
@@ -357,20 +361,16 @@ def commands_to_redstone_delay_structure(
|
||||
for cmd in commands:
|
||||
# print("\r 正在进行处理:",end="")
|
||||
if cmd.delay > 2:
|
||||
a_max = max(a,a_max)
|
||||
a_max = max(a, a_max)
|
||||
total_cmd += (a := 1)
|
||||
else:
|
||||
a += 1
|
||||
|
||||
struct = Structure(
|
||||
size=(
|
||||
round(delay_length / 2 + total_cmd)
|
||||
if extensioon_direction == x
|
||||
else a_max,
|
||||
round(delay_length / 2 + total_cmd) if extensioon_direction == x else a_max,
|
||||
3,
|
||||
round(delay_length / 2 + total_cmd)
|
||||
if extensioon_direction == z
|
||||
else a_max,
|
||||
round(delay_length / 2 + total_cmd) if extensioon_direction == z else a_max,
|
||||
),
|
||||
fill=Block("minecraft", "air", compability_version=compability_version_),
|
||||
compability_version=compability_version_,
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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 ..main import MidiConvert
|
||||
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 = (
|
||||
perc_inst_to_soundID_withX(InstID)
|
||||
if SpecialBits
|
||||
else inst_to_souldID_withX(InstID)
|
||||
else inst_to_sould_with_deviation(InstID)
|
||||
)
|
||||
except UnboundLocalError as E:
|
||||
soundID, _X = (
|
||||
perc_inst_to_soundID_withX(-1)
|
||||
if SpecialBits
|
||||
else inst_to_souldID_withX(-1)
|
||||
else inst_to_sould_with_deviation(-1)
|
||||
)
|
||||
score_now = round(msg[-1] / float(speed) / 50)
|
||||
# print(score_now)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
用以生成Schematic结构的附加功能
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"""
|
||||
用以启动WebSocket服务器播放的附加功能
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -20,6 +20,7 @@ from .main import MidiConvert, mido
|
||||
from .subclass import *
|
||||
from .types import ChannelType
|
||||
from .utils import *
|
||||
from .constants import *
|
||||
|
||||
|
||||
class ObsoleteMidiConvert(MidiConvert):
|
||||
@@ -153,9 +154,13 @@ class ObsoleteMidiConvert(MidiConvert):
|
||||
)
|
||||
maxscore = max(maxscore, nowscore)
|
||||
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:
|
||||
soundID, _X = inst_to_souldID_withX(instrumentID)
|
||||
soundID, _X = inst_to_sould_with_deviation(
|
||||
instrumentID, MM_CLASSIC_PITCHED_INSTRUMENT_TABLE
|
||||
)
|
||||
|
||||
singleTrack.append(
|
||||
"execute @a[scores={"
|
||||
@@ -212,7 +217,14 @@ class ObsoleteMidiConvert(MidiConvert):
|
||||
(ticks * tempo) / ((self.midi.ticks_per_beat * float(speed)) * 50000) # type: ignore
|
||||
)
|
||||
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(
|
||||
"execute @a[scores={"
|
||||
+ str(scoreboardname)
|
||||
@@ -273,9 +285,13 @@ class ObsoleteMidiConvert(MidiConvert):
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
soundID, _X = (
|
||||
perc_inst_to_soundID_withX(msg[1])
|
||||
inst_to_sould_with_deviation(
|
||||
msg[1], MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE
|
||||
)
|
||||
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)
|
||||
maxScore = max(maxScore, score_now)
|
||||
@@ -339,7 +355,15 @@ class ObsoleteMidiConvert(MidiConvert):
|
||||
(ticks * tempo)
|
||||
/ ((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:
|
||||
tracks[now_tick].append(
|
||||
self.execute_cmd_head.format(player)
|
||||
@@ -413,9 +437,13 @@ class ObsoleteMidiConvert(MidiConvert):
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
soundID, _X = (
|
||||
perc_inst_to_soundID_withX(msg[1])
|
||||
inst_to_sould_with_deviation(
|
||||
msg[1], MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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 typing import Optional
|
||||
from typing import Any
|
||||
from .types import Optional, Any, List, Mapping
|
||||
|
||||
from .constants import PERCUSSION_INSTRUMENT_LIST
|
||||
from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX, volume2distance
|
||||
from .constants import MC_PERCUSSION_INSTRUMENT_LIST
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
@@ -49,6 +49,9 @@ class SingleNote:
|
||||
percussive: bool
|
||||
"""是否为打击乐器"""
|
||||
|
||||
extra_info: Any
|
||||
"""你觉得放什么好?"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
instrument: int,
|
||||
@@ -58,6 +61,7 @@ class SingleNote:
|
||||
lastime: int,
|
||||
track_number: int = 0,
|
||||
is_percussion: Optional[bool] = None,
|
||||
extra_information: Any = None,
|
||||
):
|
||||
"""用于存储单个音符的类
|
||||
:param instrument 乐器编号
|
||||
@@ -80,12 +84,14 @@ class SingleNote:
|
||||
"""音符所处的音轨"""
|
||||
|
||||
self.percussive = (
|
||||
(is_percussion in PERCUSSION_INSTRUMENT_LIST)
|
||||
(is_percussion in MC_PERCUSSION_INSTRUMENT_LIST)
|
||||
if (is_percussion is None)
|
||||
else is_percussion
|
||||
)
|
||||
"""是否为打击乐器"""
|
||||
|
||||
self.extra_info = extra_information
|
||||
|
||||
@property
|
||||
def inst(self) -> int:
|
||||
"""乐器编号"""
|
||||
@@ -100,14 +106,14 @@ class SingleNote:
|
||||
"""音符编号"""
|
||||
return self.note
|
||||
|
||||
@property
|
||||
def get_mc_pitch(self) -> float:
|
||||
self.mc_sound_ID, _X = (
|
||||
perc_inst_to_soundID_withX(self.inst)
|
||||
if self.percussive
|
||||
else inst_to_souldID_withX(self.inst)
|
||||
)
|
||||
return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
|
||||
# @property
|
||||
# def get_mc_pitch(self,table: Dict[int, Tuple[str, int]]) -> float:
|
||||
# self.mc_sound_ID, _X = inst_to_sould_with_deviation(self.inst,table,"note.bd" if self.percussive else "note.flute",)
|
||||
# return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
|
||||
|
||||
def set_info(self, sth: Any):
|
||||
"""设置附加信息"""
|
||||
self.extra_info = sth
|
||||
|
||||
def __str__(self, is_track: bool = False):
|
||||
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format(
|
||||
@@ -168,31 +174,6 @@ class SingleNote:
|
||||
return False
|
||||
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)
|
||||
class SingleCommand:
|
||||
@@ -304,7 +285,7 @@ class SingleNoteBox:
|
||||
self.annotation_text = annotation
|
||||
"""音符注释"""
|
||||
if percussion is None:
|
||||
self.is_percussion = percussion in PERCUSSION_INSTRUMENT_LIST
|
||||
self.is_percussion = percussion in MC_PERCUSSION_INSTRUMENT_LIST
|
||||
else:
|
||||
self.is_percussion = percussion
|
||||
|
||||
@@ -359,3 +340,62 @@ class SingleNoteBox:
|
||||
if not isinstance(other, self.__class__):
|
||||
return False
|
||||
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,],],]
|
||||
"""
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
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
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 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
|
||||
|
||||
ProgressStyle = Tuple[str, Tuple[str, str]]
|
||||
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
|
||||
"""
|
||||
进度条样式类型
|
||||
Midi音符名称对照表类型
|
||||
"""
|
||||
|
||||
VoidMido = Union[mido.MidiFile, None] # void mido
|
||||
MidiInstrumentTableType = Mapping[int, Tuple[str, int]]
|
||||
"""
|
||||
空Midi类类型
|
||||
Midi乐器对照表类型
|
||||
"""
|
||||
|
||||
|
||||
NoteChannelType = Dict[
|
||||
int,
|
||||
List[SingleNote,],
|
||||
]
|
||||
"""
|
||||
频道信息类型
|
||||
|
||||
Dict[int,Dict[int,List[SingleNote,],],]
|
||||
"""
|
||||
FittingFunctionType = Callable[[float], float]
|
||||
|
||||
|
||||
ChannelType = Dict[
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 仓库根目录下的 License.md
|
||||
Terms & Conditions: License.md in the root directory
|
||||
@@ -16,9 +16,21 @@ Terms & Conditions: License.md in the root directory
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
import math
|
||||
import random
|
||||
|
||||
from .constants import PERCUSSION_INSTRUMENT_TABLE, PITCHED_INSTRUMENT_TABLE
|
||||
from typing import Any, Dict, Tuple
|
||||
from .constants import MM_INSTRUMENT_DEVIATION_TABLE, MC_INSTRUMENT_BLOCKS_TABLE
|
||||
from .subclass import SingleNote
|
||||
|
||||
from .types import (
|
||||
Any,
|
||||
Dict,
|
||||
Tuple,
|
||||
Optional,
|
||||
Callable,
|
||||
Literal,
|
||||
Union,
|
||||
MidiInstrumentTableType,
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
reference_table: MidiInstrumentTableType,
|
||||
default_instrument: str = "note.flute",
|
||||
default_deviation: Optional[int] = 5,
|
||||
) -> Tuple[str, int]:
|
||||
"""
|
||||
返回midi的乐器ID对应的我的世界乐器名,对于音域转换算法,如下:
|
||||
@@ -60,40 +75,32 @@ def inst_to_souldID_withX(
|
||||
----------
|
||||
instrumentID: int
|
||||
midi的乐器ID
|
||||
reference_table: Dict[int, Tuple[str, int]]
|
||||
转换乐器参照表
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple(str我的世界乐器名, int转换算法中的X)
|
||||
"""
|
||||
try:
|
||||
return PITCHED_INSTRUMENT_TABLE[instrumentID]
|
||||
except KeyError:
|
||||
return "note.flute", 5
|
||||
|
||||
|
||||
def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]:
|
||||
"""
|
||||
对于Midi第10通道所对应的打击乐器,返回我的世界乐器名
|
||||
|
||||
Parameters
|
||||
----------
|
||||
instrumentID: int
|
||||
midi的乐器ID
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple(str我的世界乐器名, int转换算法中的X)
|
||||
"""
|
||||
try:
|
||||
return PERCUSSION_INSTRUMENT_TABLE[instrumentID]
|
||||
except KeyError:
|
||||
return "note.bd", 7
|
||||
return reference_table.get(
|
||||
instrumentID,
|
||||
(
|
||||
default_instrument,
|
||||
(
|
||||
default_deviation
|
||||
if default_deviation
|
||||
else MM_INSTRUMENT_DEVIATION_TABLE.get(default_instrument, -1)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# 明明已经走了
|
||||
# 凭什么还要在我心里留下缠绵缱绻
|
||||
|
||||
|
||||
def volume2distance(vol: float) -> float:
|
||||
def natural_curve(
|
||||
vol: float,
|
||||
) -> float:
|
||||
"""
|
||||
midi力度值拟合成的距离函数
|
||||
|
||||
@@ -117,3 +124,102 @@ def volume2distance(vol: float) -> float:
|
||||
+ -6.313841334963396 * (vol + 2592.272889454798)
|
||||
+ 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
70
Packer/MSCT_Packer.py
Normal 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_msct_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_msct_pack(MSCT_MAIN, "./Packer/MSCT_MAIN.MPK").hexdigest())
|
||||
f.write("\nMSCT_PLUGIN:\n")
|
||||
f.write(enpack_msct_pack(MSCT_PLUGIN, "./Packer/MSCT_PLUGIN.MPK").hexdigest())
|
||||
f.write("\nMSCT_PLUGIN_FUNCTION:\n")
|
||||
f.write(
|
||||
enpack_msct_pack(
|
||||
MSCT_PLUGIN_FUNCTION, "./Packer/MSCT_PLUGIN_FUNCTION.MPK"
|
||||
).hexdigest()
|
||||
)
|
||||
@@ -50,7 +50,7 @@
|
||||
pip install --upgrade -i https://pypi.python.org/simple Musicreater
|
||||
```
|
||||
|
||||
- 克隆仓库并安装(**不推荐**)
|
||||
- 克隆仓库并安装(最新版本但**不推荐**)
|
||||
```bash
|
||||
git clone https://gitee.com/TriM-Organization/Musicreater.git
|
||||
cd Musicreater
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
- Clone repo and Install (**NOT RECOMMANDED**):
|
||||
- Clone repo and Install (Latest but **NOT RECOMMANDED**):
|
||||
```bash
|
||||
git clone https://github.com/TriM-Organization/Musicreater.git
|
||||
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
|
||||
|
||||
## Thanks 🙏
|
||||
## Acknowledgements 🙏
|
||||
|
||||
This list is not in any order.
|
||||
|
||||
|
||||
@@ -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)|
|
||||
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度。以 $S$ 表示此参数`Ht`,以Vol表示音量百分比,则计算公式为: $S = \frac{1}{Vol}-1$ |
|
||||
|`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` 作为进度条字幕。
|
||||
|
||||
哦对了,上面的只不过是样式定义,同时还需要定义的是可变图形的部分,也就是进度条上那个真正的“条”。
|
||||
|
||||
对于这个我们就采用了固定参数的方法,对于一个进度条,无非就是“已经播放过的”和“没播放过的”两种形态,所以,使用一个元组来传入这两个参数就是最简单的了。元组的格式也很简单:`(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",
|
||||
)
|
||||
```
|
||||
|
||||
*为了避免生成错误,请尽量避免使用标识符作为定义样式字符串的其他部分*
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
**_使用时请遵循协议规定_**
|
||||
|
||||
- 版权所有 © 2023 音·创 开发者
|
||||
- Copyright © 2023 all the developers of Musicreater
|
||||
- 版权所有 © 2024 音·创 开发者
|
||||
- Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
* 开源相关声明请见 仓库根目录下的 License.md
|
||||
* Terms & Conditions: License.md in the root directory
|
||||
|
||||
142
example.py
142
example.py
@@ -9,8 +9,8 @@
|
||||
Musicreater (音·创)
|
||||
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
|
||||
|
||||
版权所有 © 2023 音·创 开发者
|
||||
Copyright © 2023 all the developers of Musicreater
|
||||
版权所有 © 2024 音·创 开发者
|
||||
Copyright © 2024 all the developers of Musicreater
|
||||
|
||||
开源相关声明请见 ./License.md
|
||||
Terms & Conditions: ./License.md
|
||||
@@ -25,6 +25,12 @@ from Musicreater.plugin.addonpack import (
|
||||
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
|
||||
|
||||
# 获取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())
|
||||
|
||||
|
||||
@@ -50,7 +58,17 @@ def bool_str(sth: str):
|
||||
elif str(sth).lower() in ("false", "假", "否", "f", "n"):
|
||||
return False
|
||||
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"):
|
||||
@@ -74,31 +92,63 @@ else:
|
||||
bool_str,
|
||||
),
|
||||
(
|
||||
f"计分板名称:",
|
||||
str,
|
||||
)
|
||||
if playerFormat == 1
|
||||
else (
|
||||
f"玩家选择器:",
|
||||
str,
|
||||
(
|
||||
f"计分板名称:",
|
||||
str,
|
||||
)
|
||||
if playerFormat == 1
|
||||
else (
|
||||
f"玩家选择器:",
|
||||
str,
|
||||
)
|
||||
),
|
||||
(
|
||||
f"是否自动重置计分板:",
|
||||
bool_str,
|
||||
)
|
||||
if playerFormat == 1
|
||||
else (),
|
||||
(
|
||||
f"是否自动重置计分板:",
|
||||
bool_str,
|
||||
)
|
||||
if playerFormat == 1
|
||||
else ()
|
||||
),
|
||||
(
|
||||
f"作者名称:",
|
||||
str,
|
||||
)
|
||||
if fileFormat == 1
|
||||
else (),
|
||||
()
|
||||
if playerFormat == 1
|
||||
else (
|
||||
f"最大结构高度:",
|
||||
int,
|
||||
(
|
||||
f"BDX作者署名:",
|
||||
str,
|
||||
)
|
||||
if fileFormat == 1
|
||||
else (
|
||||
(
|
||||
(
|
||||
"结构延展方向:",
|
||||
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:
|
||||
@@ -109,12 +159,20 @@ print(f"正在处理 {midi_path} :")
|
||||
cvt_mid = Musicreater.MidiConvert.from_midi_file(midi_path, old_exe_format=False)
|
||||
cvt_cfg = ConvertConfig(out_path, *prompts[:3])
|
||||
|
||||
if playerFormat == 1:
|
||||
cvt_method = to_addon_pack_in_score
|
||||
elif playerFormat == 0:
|
||||
cvt_method = to_addon_pack_in_delay
|
||||
elif playerFormat == 2:
|
||||
cvt_method = to_addon_pack_in_repeater
|
||||
if fileFormat == 0:
|
||||
if playerFormat == 1:
|
||||
cvt_method = to_addon_pack_in_score
|
||||
elif playerFormat == 0:
|
||||
cvt_method = to_addon_pack_in_delay
|
||||
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(
|
||||
@@ -122,11 +180,21 @@ print(
|
||||
*(cvt_method(cvt_mid, cvt_cfg, *prompts[3:])) # type: ignore
|
||||
)
|
||||
if fileFormat == 0
|
||||
else " 指令总长:{},最高延迟:{},结构大小{},终点坐标{}".format(
|
||||
*(
|
||||
to_BDX_file_in_score(cvt_mid, cvt_cfg, *prompts[3:])
|
||||
if playerFormat == 1
|
||||
else to_BDX_file_in_delay(cvt_mid, cvt_cfg, *prompts[3:])
|
||||
else (
|
||||
" 指令总长:{},最高延迟:{},结构大小{},终点坐标{}".format(
|
||||
*(
|
||||
to_BDX_file_in_score(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
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
@@ -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),
|
||||
)
|
||||
)
|
||||
@@ -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),
|
||||
)
|
||||
)
|
||||
@@ -11,4 +11,4 @@
|
||||
不得用于商业用途
|
||||
若 音·创 库被用于商业用途,应当将其剔除
|
||||
|
||||
版权所有 © 2023 诸葛亮与八卦阵
|
||||
版权所有 © 2024 诸葛亮与八卦阵
|
||||
Reference in New Issue
Block a user