Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver

This commit is contained in:
EillesWan 2022-07-12 11:46:49 +08:00
commit 6f6a77d0b4
7 changed files with 329 additions and 178 deletions

3
.gitignore vendored
View File

@ -140,3 +140,6 @@ dmypy.json
# Cython debug symbols # Cython debug symbols
cython_debug/ cython_debug/
# Pycharm
/.idea

View File

@ -58,6 +58,8 @@
> >
> `pip install brotli` > `pip install brotli`
> >
> `pip install openpyxl`
>
> 3. 开始使用! > 3. 开始使用!
> 在目录下打开cmd进入到目录下执行以下命令(选择你需要的) > 在目录下打开cmd进入到目录下执行以下命令(选择你需要的)
> >
@ -111,7 +113,8 @@
## 致谢🙏 ## 致谢🙏
- 感谢 昀梦\<QQ1515399885\> 找出指令生成错误bug并指正 - 感谢 昀梦\<QQ1515399885\> 找出指令生成错误bug并指正
- 感谢由 Charlie_Ping “查理平” 带来的bdx文件转换参考 - 感谢由 Charlie_Ping “查理平” 带来的bdx文件转换参考
以及mid转我的世界乐器参考表格
- 感谢由 CMA_2401PT 为我们的软件开发进行指导 - 感谢由 CMA_2401PT 为我们的软件开发进行指导
- 感谢由 Dislink Sforza \<QQ1600515314\>带来的midi音色解析以及转换指令的算法我们将其加入了我们众多算法之一 - 感谢由 Dislink Sforza \<QQ1600515314\>带来的midi音色解析以及转换指令的算法我们将其加入了我们众多算法之一
- 感谢 Touch \<QQ1793537164\>提供的测试支持 - 感谢 Touch \<QQ1793537164\>提供的测试支持

View File

@ -66,6 +66,8 @@ A simple Python package.
> >
> `pip install brotli` > `pip install brotli`
> >
> `pip install openpyxl`
>
> 3. Start using! > 3. Start using!
> >
> Open CMD in the directory, enter the directory, and execute the following commands: > Open CMD in the directory, enter the directory, and execute the following commands:
@ -123,7 +125,8 @@ This is a default definder parameter:
- Thank [Fuckcraft](https://github.com/fuckcraft) *(“鸣凤鸽子” ,etc)* for the function of Creating the Websocket Server for Minecraft: Bedrock Edition. - Thank [Fuckcraft](https://github.com/fuckcraft) *(“鸣凤鸽子” ,etc)* for the function of Creating the Websocket Server for Minecraft: Bedrock Edition.
- *!! They have given me the rights to directly copy the lib into Musicreater* - *!! They have given me the rights to directly copy the lib into Musicreater*
- Thank *昀梦*\<QQ1515399885\> for finding and correcting the bugs in the commands that *Musicreater* Created. - Thank *昀梦*\<QQ1515399885\> for finding and correcting the bugs in the commands that *Musicreater* Created.
- Thank *Charlie_Ping “查理平”* for bdx convert funtion. - Thank *Charlie_Ping “查理平”* for bdx convert function, and
the data label that's used to convert the mid's instruments into minecraft's instruments.
- Thank *CMA_2401PT* for BDXWorkShop as the .bdx structure's operation guide. - Thank *CMA_2401PT* for BDXWorkShop as the .bdx structure's operation guide.
- Thank *Miracle Plume “神羽”* \<QQshenyu40403\> for the Miracle Plume Bedrock Edition Audio Resource Pack - Thank *Miracle Plume “神羽”* \<QQshenyu40403\> for the Miracle Plume Bedrock Edition Audio Resource Pack
- 感谢由 Dislink Sforza \<QQ1600515314\>带来的midi转换算法我们将其加入了我们众多算法之一 - 感谢由 Dislink Sforza \<QQ1600515314\>带来的midi转换算法我们将其加入了我们众多算法之一

View File

@ -13,3 +13,10 @@ convertion.tomcpack(
float(input('请输入音量0-1')), float(input('请输入音量0-1')),
float(input('请输入速度倍率:')), float(input('请输入速度倍率:')),
) )
# for the test
# if __name__ == '__main__':
# convertion = midiConvert()
# convertion.convert(r"C:\Users\lc\Documents\MuseScore3\乐谱\乐谱\victory.mid", ".")
# convertion.tomcpack(
# 1, True, True, "scb", 1, 1)

View File

@ -33,6 +33,9 @@ Note! Except for this source file, all the files in this repository and this pro
import os import os
import mido import mido
import brotli import brotli
import json
import uuid
import shutil
def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
@ -45,7 +48,7 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
""" """
import zipfile import zipfile
zipf = zipfile.ZipFile(outFilename, 'w', compression) zipf = zipfile.ZipFile(outFilename, "w", compression)
pre_len = len(os.path.dirname(sourceDir)) pre_len = len(os.path.dirname(sourceDir))
for parent, dirnames, filenames in os.walk(sourceDir): for parent, dirnames, filenames in os.walk(sourceDir):
for filename in filenames: for filename in filenames:
@ -59,21 +62,21 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
class midiConvert: class midiConvert:
def __init__(self): def __init__(self):
'''简单的midi转换类将midi文件转换为我的世界结构或者包''' """简单的midi转换类将midi文件转换为我的世界结构或者包"""
pass pass
def convert(self, midiFile: str, outputPath: str): def convert(self, midiFile: str, outputPath: str):
'''转换前需要先运行此函数来获取基本信息''' """转换前需要先运行此函数来获取基本信息"""
self.midiFile = midiFile self.midiFile = midiFile
'''midi文件路径''' """midi文件路径"""
self.midi = mido.MidiFile(self.midiFile) self.midi = mido.MidiFile(self.midiFile)
'''MidiFile对象''' """MidiFile对象"""
self.outputPath = outputPath self.outputPath = outputPath
'''输出路径''' """输出路径"""
# 将self.midiFile的文件名不含路径且不含后缀存入self.midiFileName # 将self.midiFile的文件名不含路径且不含后缀存入self.midiFileName
self.midFileName = os.path.splitext(os.path.basename(self.midiFile))[0] self.midFileName = os.path.splitext(os.path.basename(self.midiFile))[0]
'''文件名,不含路径且不含后缀''' """文件名,不含路径且不含后缀"""
def __Inst2soundIDwithX(self, instrumentID): def __Inst2soundIDwithX(self, instrumentID):
"""返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下 """返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下
@ -84,59 +87,159 @@ class midiConvert:
贝斯bass迪吉里杜管didgeridoo的时候为8 贝斯bass迪吉里杜管didgeridoo的时候为8
长笛flute牛铃cou_bell的时候为5 长笛flute牛铃cou_bell的时候为5
钟琴bell管钟chime木琴xylophone的时候为4 钟琴bell管钟chime木琴xylophone的时候为4
而存在一些打击乐器basedrumhatsnare没有音域则没有X那么我们返回7即可
:param instrumentID: midi的乐器ID :param instrumentID: midi的乐器ID
:param default: 如果instrumentID不在范围内返回的默认我的世界乐器名称 :param default: 如果instrumentID不在范围内返回的默认我的世界乐器名称
:return: (str我的世界乐器名, int转换算法中的X)""" :return: (str我的世界乐器名, int转换算法中的X)"""
if instrumentID == 105: return {
return 'note.banjo', 6 0: ("note.harp", 6),
if instrumentID in range(32, 40): 1: ("note.harp", 6),
return 'note.bass', 8 2: ("note.pling", 6),
if instrumentID in range(115, 119): 3: ("note.harp", 6),
return 'note.basedrum', 7 # 注意,这里是底鼓,打击乐器无音域 4: ("note.pling", 6),
if instrumentID == 9 or instrumentID == 14: 5: ("note.pling", 6),
return 'note.bell', 4 6: ("note.harp", 6),
if instrumentID == 80 or instrumentID == 81: 7: ("note.harp", 6),
return 'note.bit', 6 8: ("note.share", 7), # 打击乐器无音域
if instrumentID == 112: 9: ("note.harp", 6),
return 'note.cow_bell', 5 10: ("note.didgeridoo", 8),
if instrumentID == -1: 11: ("note.harp", 6),
return 'note.didgeridoo', 8 12: ("note.xylophone", 4),
if instrumentID in range(72, 80): 13: ("note.chime", 4),
return 'note.flute', 5 14: ("note.harp", 6),
if instrumentID in range(24, 32): 15: ("note.harp", 6),
return 'note.guitar', 7 16: ("note.bass", 8),
if instrumentID == -2: 17: ("note.harp", 6),
return 'note.hat', 7 # 注意,这里是击鼓沿,打击乐器无音域 18: ("note.harp", 6),
if instrumentID == 14: 19: ("note.harp", 6),
return 'note.chime', 4 20: ("note.harp", 6),
if instrumentID == 8 or instrumentID == 11: 21: ("note.harp", 6),
return 'iron_xylophone', 6 22: ("note.harp", 6),
if instrumentID == 2: 23: ("note.guitar", 7),
return 'note.pling', 6 24: ("note.guitar", 7),
if instrumentID == 114: 25: ("note.guitar", 7),
return 'note.snare', 7 # 注意,这里是小军鼓,打击乐器无音域 26: ("note.guitar", 7),
if instrumentID == 13: 27: ("note.guitar", 7),
return 'note.xylophone', 4 28: ("note.guitar", 7),
return 'note.harp', 6 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.basedrum", 7), # 打击乐器无音域
117: ("note.bass", 8),
118: ("note.bit", 6),
119: ("note.basedrum", 7), # 打击乐器无音域
120: ("note.guitar", 7),
121: ("note.harp", 6),
122: ("note.harp", 6),
123: ("note.harp", 6),
124: ("note.harp", 6),
125: ("note.hat", 7), # 打击乐器无音域
126: ("note.basedrum", 7), # 打击乐器无音域
127: ("note.snare", 7), # 打击乐器无音域
}[instrumentID]
def __score2time(self, score: int): def __score2time(self, score: int):
return str(int(int(score / 20) / 60)) + ':' + str(int(int(score / 20) % 60)) return str(int(int(score / 20) / 60)) + ":" + str(int(int(score / 20) % 60))
def __formProgressBar( def __formProgressBar(
self, self,
maxscore: int, maxscore: int,
scoreboardname: str, scoreboardname: str,
progressbar: tuple = ( progressbar: tuple = (
r'%%N [ %%s/%^s %%% __________ %%t|%^t ]', r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
('§e=§r', '§7=§r'), ("§e=§r", "§7=§r"),
), ),
) -> list: ) -> list:
pgsstyle = progressbar[0] pgsstyle = progressbar[0]
'''用于被替换的进度条原始样式''' """用于被替换的进度条原始样式"""
''' """
| 标识符 | 指定的可变量 | | 标识符 | 指定的可变量 |
|---------|----------------| |---------|----------------|
| `%%N` | 乐曲名(即传入的文件名)| | `%%N` | 乐曲名(即传入的文件名)|
@ -146,7 +249,7 @@ class midiConvert:
| `%^t` | 曲目总时长 | | `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 | | `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位| | `_` | 用以表示进度条占位|
''' """
def __replace( def __replace(
s: str, tobeReplaced: str, replaceWith: str, times: int, other: str s: str, tobeReplaced: str, replaceWith: str, times: int, other: str
@ -155,7 +258,7 @@ class midiConvert:
return s.replace(tobeReplaced, other) return s.replace(tobeReplaced, other)
if times == s.count(tobeReplaced): if times == s.count(tobeReplaced):
return s.replace(tobeReplaced, replaceWith) return s.replace(tobeReplaced, replaceWith)
result = '' result = ""
t = 0 t = 0
for i in s: for i in s:
if i == tobeReplaced: if i == tobeReplaced:
@ -170,12 +273,12 @@ class midiConvert:
return result return result
idlist = { idlist = {
r'%%N': self.midFileName, r"%%N": self.midFileName,
r'%%s': r'%%s', r"%%s": r"%%s",
r'%^s': str(maxscore), r"%^s": str(maxscore),
r'%%t': r'%%t', r"%%t": r"%%t",
r'%^t': self.__score2time(maxscore), r"%^t": self.__score2time(maxscore),
r'%%%': r'%%%', r"%%%": r"%%%",
} }
ids = {} ids = {}
@ -192,32 +295,32 @@ class midiConvert:
del idlist del idlist
pgblength = pgsstyle.count('_') pgblength = pgsstyle.count("_")
'''进度条的“条”长度''' """进度条的“条”长度"""
finalprgsbar = [] finalprgsbar = []
for i in range(maxscore): for i in range(maxscore):
nowstr = pgsstyle nowstr = pgsstyle
if ids[r'%%s'] == True: if ids[r"%%s"] == True:
nowstr = nowstr.replace(r'%%s', str(i + 1)) nowstr = nowstr.replace(r"%%s", str(i + 1))
if ids[r'%%t'] == True: if ids[r"%%t"] == True:
nowstr = nowstr.replace(r'%%t', self.__score2time(i + 1)) nowstr = nowstr.replace(r"%%t", self.__score2time(i + 1))
if ids[r'%%%'] == True: if ids[r"%%%"] == True:
nowstr = nowstr.replace( nowstr = nowstr.replace(
r'%%%', str(int((i + 1) / maxscore * 10000) / 100) + '%' r"%%%", str(int((i + 1) / maxscore * 10000) / 100) + "%"
) )
countof_s = int((i + 1) / maxscore * pgblength) countof_s = int((i + 1) / maxscore * pgblength)
finalprgsbar.append( finalprgsbar.append(
'title @a[scores={' "title @a[scores={"
+ scoreboardname + scoreboardname
+ '=' + "="
+ str(i + 1) + str(i + 1)
+ '}] actionbar ' + "}] actionbar "
+ __replace( + __replace(
nowstr, '_', progressbar[1][0], countof_s, progressbar[1][1] nowstr, "_", progressbar[1][0], countof_s, progressbar[1][1]
) )
) )
@ -231,7 +334,7 @@ class midiConvert:
condition: bool = False, condition: bool = False,
needRedstone: bool = True, needRedstone: bool = True,
tickDelay: int = 0, tickDelay: int = 0,
customName: str = '', customName: str = "",
executeOnFirstTick: bool = False, executeOnFirstTick: bool = False,
trackOutput: bool = True, trackOutput: bool = True,
): ):
@ -285,7 +388,7 @@ class midiConvert:
impluse.to_bytes(4, byteorder="big", signed=False), impluse.to_bytes(4, byteorder="big", signed=False),
bytes(command, encoding="utf-8") + b"\x00", bytes(command, encoding="utf-8") + b"\x00",
bytes(customName, encoding="utf-8") + b"\x00", bytes(customName, encoding="utf-8") + b"\x00",
bytes('', encoding="utf-8") + b"\x00", bytes("", encoding="utf-8") + b"\x00",
tickDelay.to_bytes(4, byteorder="big", signed=True), tickDelay.to_bytes(4, byteorder="big", signed=True),
executeOnFirstTick.to_bytes(1, byteorder="big"), executeOnFirstTick.to_bytes(1, byteorder="big"),
trackOutput.to_bytes(1, byteorder="big"), trackOutput.to_bytes(1, byteorder="big"),
@ -296,7 +399,7 @@ class midiConvert:
return block return block
def _toCmdList_m1( def _toCmdList_m1(
self, scoreboardname: str = 'mscplay', volume: float = 1.0, speed: float = 1.0 self, scoreboardname: str = "mscplay", volume: float = 1.0, speed: float = 1.0
) -> list: ) -> list:
""" """
使用Dislink Sforza的转换思路将midi转换为我的世界命令列表 使用Dislink Sforza的转换思路将midi转换为我的世界命令列表
@ -322,13 +425,15 @@ class midiConvert:
for msg in track: for msg in track:
ticks += msg.time ticks += msg.time
# print(msg)
if msg.is_meta: if msg.is_meta:
if msg.type == 'set_tempo': if msg.type == "set_tempo":
tempo = msg.tempo tempo = msg.tempo
if msg.type == 'program_change':
instrumentID = msg.program
else: else:
if msg.type == 'note_on' and msg.velocity != 0: if msg.type == "program_change":
# print("TT")
instrumentID = msg.program
if msg.type == "note_on" and msg.velocity != 0:
nowscore = round( nowscore = round(
(ticks * tempo) (ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000) / ((self.midi.ticks_per_beat * float(speed)) * 50000)
@ -336,12 +441,12 @@ class midiConvert:
maxscore = max(maxscore, nowscore) maxscore = max(maxscore, nowscore)
soundID, _X = self.__Inst2soundIDwithX(instrumentID) soundID, _X = self.__Inst2soundIDwithX(instrumentID)
singleTrack.append( singleTrack.append(
'execute @a[scores={' "execute @a[scores={"
+ str(scoreboardname) + str(scoreboardname)
+ '=' + "="
+ str(nowscore) + str(nowscore)
+ '}' + "}"
+ f'] ~ ~ ~ playsound {soundID} @s ~ ~{1/volume-1} ~ {msg.velocity*(0.7 if msg.channel == 0 else 0.9)} {2**((msg.note-60-_X)/12)}' + f"] ~ ~ ~ playsound {soundID} @s ~ ~{1 / volume - 1} ~ {msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}"
) )
commands += 1 commands += 1
if len(singleTrack) != 0: if len(singleTrack) != 0:
@ -353,7 +458,7 @@ class midiConvert:
self, self,
volume: float = 1.0, volume: float = 1.0,
speed: float = 1.0, speed: float = 1.0,
player: str = '@a', player: str = "@a",
isMixedWithPrograssBar=False, isMixedWithPrograssBar=False,
) -> list: ) -> list:
""" """
@ -373,8 +478,8 @@ class midiConvert:
if isMixedWithPrograssBar == True: if isMixedWithPrograssBar == True:
isMixedWithPrograssBar = ( isMixedWithPrograssBar = (
r'%%N [ %%s/%^s %%% __________ %%t|%^t ]', r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
('§e=§r', '§7=§r'), ("§e=§r", "§7=§r"),
) )
for i, track in enumerate(self.midi.tracks): for i, track in enumerate(self.midi.tracks):
@ -385,12 +490,12 @@ class midiConvert:
for msg in track: for msg in track:
ticks += msg.time ticks += msg.time
if msg.is_meta: if msg.is_meta:
if msg.type == 'set_tempo': if msg.type == "set_tempo":
tempo = msg.tempo tempo = msg.tempo
if msg.type == 'program_change':
instrumentID = msg.program
else: else:
if msg.type == 'note_on' and msg.velocity != 0: if msg.type == "program_change":
instrumentID = msg.program
if msg.type == "note_on" and msg.velocity != 0:
nowtick = round( nowtick = round(
(ticks * tempo) (ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000) / ((self.midi.ticks_per_beat * float(speed)) * 50000)
@ -398,11 +503,11 @@ class midiConvert:
soundID, _X = self.__Inst2soundIDwithX(instrumentID) soundID, _X = self.__Inst2soundIDwithX(instrumentID)
try: try:
tracks[nowtick].append( tracks[nowtick].append(
f'execute {player} ~ ~ ~ playsound {soundID} @s ~ ~{1/volume-1} ~ {msg.velocity*(0.7 if msg.channel == 0 else 0.9)} {2**((msg.note-60-_X)/12)}' f"execute {player} ~ ~ ~ playsound {soundID} @s ~ ~{1 / volume - 1} ~ {msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}"
) )
except: except:
tracks[nowtick] = [ tracks[nowtick] = [
f'execute {player} ~ ~ ~ playsound {soundID} @s ~ ~{1/volume-1} ~ {msg.velocity*(0.7 if msg.channel == 0 else 0.9)} {2**((msg.note-60-_X)/12)}', f"execute {player} ~ ~ ~ playsound {soundID} @s ~ ~{1 / volume - 1} ~ {msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}",
] ]
allticks = list(tracks.keys()) allticks = list(tracks.keys())
@ -410,9 +515,9 @@ class midiConvert:
if isMixedWithPrograssBar: if isMixedWithPrograssBar:
pgsstyle = isMixedWithPrograssBar[0] pgsstyle = isMixedWithPrograssBar[0]
'''用于被替换的进度条原始样式''' """用于被替换的进度条原始样式"""
''' """
| 标识符 | 指定的可变量 | | 标识符 | 指定的可变量 |
|---------|----------------| |---------|----------------|
| `%%N` | 乐曲名(即传入的文件名)| | `%%N` | 乐曲名(即传入的文件名)|
@ -422,7 +527,7 @@ class midiConvert:
| `%^t` | 曲目总时长 | | `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 | | `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位| | `_` | 用以表示进度条占位|
''' """
def __replace( def __replace(
s: str, tobeReplaced: str, replaceWith: str, times: int, other: str s: str, tobeReplaced: str, replaceWith: str, times: int, other: str
@ -431,7 +536,7 @@ class midiConvert:
return s.replace(tobeReplaced, other) return s.replace(tobeReplaced, other)
if times == s.count(tobeReplaced): if times == s.count(tobeReplaced):
return s.replace(tobeReplaced, replaceWith) return s.replace(tobeReplaced, replaceWith)
result = '' result = ""
t = 0 t = 0
for i in s: for i in s:
if i == tobeReplaced: if i == tobeReplaced:
@ -446,12 +551,12 @@ class midiConvert:
return result return result
idlist = { idlist = {
r'%%N': self.midFileName, r"%%N": self.midFileName,
r'%%s': r'%%s', r"%%s": r"%%s",
r'%^s': str(allticks[-1]), r"%^s": str(allticks[-1]),
r'%%t': r'%%t', r"%%t": r"%%t",
r'%^t': self.__score2time(allticks[-1]), r"%^t": self.__score2time(allticks[-1]),
r'%%%': r'%%%', r"%%%": r"%%%",
} }
ids = {} ids = {}
@ -468,8 +573,8 @@ class midiConvert:
del idlist del idlist
pgblength = pgsstyle.count('_') pgblength = pgsstyle.count("_")
'''进度条的“条”长度''' """进度条的“条”长度"""
results = [] results = []
@ -489,34 +594,40 @@ class midiConvert:
if isMixedWithPrograssBar: if isMixedWithPrograssBar:
nowstr = pgsstyle nowstr = pgsstyle
if ids[r'%%s'] == True: if ids[r"%%s"] == True:
nowstr = nowstr.replace(r'%%s', str(allticks[i] + 1)) nowstr = nowstr.replace(r"%%s", str(allticks[i] + 1))
if ids[r'%%t'] == True: if ids[r"%%t"] == True:
nowstr = nowstr.replace(r'%%t', self.__score2time(allticks[i] + 1)) nowstr = nowstr.replace(r"%%t", self.__score2time(allticks[i] + 1))
if ids[r'%%%'] == True: if ids[r"%%%"] == True:
nowstr = nowstr.replace( nowstr = nowstr.replace(
r'%%%', str(int((allticks[i] + 1) / allticks[-1] * 10000) / 100) + '%' r"%%%",
str(int((allticks[i] + 1) / allticks[-1] * 10000) / 100) + "%",
) )
countof_s = int((allticks[i] + 1) / allticks[-1] * pgblength) countof_s = int((allticks[i] + 1) / allticks[-1] * pgblength)
titlenow = __replace( titlenow = __replace(
nowstr, nowstr,
'_', "_",
isMixedWithPrograssBar[1][0], isMixedWithPrograssBar[1][0],
countof_s, countof_s,
isMixedWithPrograssBar[1][1], isMixedWithPrograssBar[1][1],
) )
results.append((f'title {player} actionbar {titlenow}', 0,)) results.append(
(
f"title {player} actionbar {titlenow}",
0,
)
)
return results return results
def __fillSquareSideLength(self, total: int, maxHeight: int): def __fillSquareSideLength(self, total: int, maxHeight: int):
'''给定总方块数量和最大高度,返回所构成的图形外切正方形的边长 """给定总方块数量和最大高度,返回所构成的图形外切正方形的边长
:param total: 总方块数量 :param total: 总方块数量
:param maxHeight: 最大高度 :param maxHeight: 最大高度
:return: 外切正方形的边长 int''' :return: 外切正方形的边长 int"""
import math import math
return math.ceil(math.sqrt(math.ceil(total / maxHeight))) return math.ceil(math.sqrt(math.ceil(total / maxHeight)))
@ -526,7 +637,7 @@ class midiConvert:
method: int = 1, method: int = 1,
isAutoReset: bool = False, isAutoReset: bool = False,
progressbar=None, progressbar=None,
scoreboardname: str = 'mscplay', scoreboardname: str = "mscplay",
volume: float = 1.0, volume: float = 1.0,
speed: float = 1.0, speed: float = 1.0,
) -> bool: ) -> bool:
@ -543,106 +654,102 @@ class midiConvert:
if method == 1: if method == 1:
cmdlist, _a, maxscore = self._toCmdList_m1(scoreboardname, volume, speed) cmdlist, _a, maxscore = self._toCmdList_m1(scoreboardname, volume, speed)
else: else:
return (False, f'无法找到算法ID{method}对应的转换算法') return (False, f"无法找到算法ID{method}对应的转换算法")
del _a del _a
import json
import uuid
import shutil
# 当文件f夹{self.outputPath}/temp/functions存在时清空其下所有项目若其不存在则创建 # 当文件f夹{self.outputPath}/temp/functions存在时清空其下所有项目若其不存在则创建
if os.path.exists(f'{self.outputPath}/temp/functions/'): if os.path.exists(f"{self.outputPath}/temp/functions/"):
shutil.rmtree(f'{self.outputPath}/temp/functions/') shutil.rmtree(f"{self.outputPath}/temp/functions/")
os.makedirs(f'{self.outputPath}/temp/functions/mscplay') os.makedirs(f"{self.outputPath}/temp/functions/mscplay")
# 写入manifest.json # 写入manifest.json
if not os.path.exists(f'{self.outputPath}/temp/manifest.json'): if not os.path.exists(f"{self.outputPath}/temp/manifest.json"):
with open( with open(
f"{self.outputPath}/temp/manifest.json", "w", encoding='utf-8' f"{self.outputPath}/temp/manifest.json", "w", encoding="utf-8"
) as f: ) as f:
f.write( f.write(
"{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" '{\n "format_version": 1,\n "header": {\n "description": "'
+ self.midFileName + self.midFileName
+ " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" + ' Pack : behavior pack",\n "version": [ 0, 0, 1 ],\n "name": "'
+ self.midFileName + self.midFileName
+ "Pack\",\n \"uuid\": \"" + 'Pack",\n "uuid": "'
+ str(uuid.uuid4()) + str(uuid.uuid4())
+ "\"\n },\n \"modules\": [\n {\n \"description\": \"" + '"\n },\n "modules": [\n {\n "description": "'
+ f"the Player of the Music {self.midFileName}" + f"the Player of the Music {self.midFileName}"
+ "\",\n \"type\": \"data\",\n \"version\": [ 0, 0, 1 ],\n \"uuid\": \"" + '",\n "type": "data",\n "version": [ 0, 0, 1 ],\n "uuid": "'
+ str(uuid.uuid4()) + str(uuid.uuid4())
+ "\"\n }\n ]\n}" + '"\n }\n ]\n}'
) )
else: else:
with open( with open(
f'{self.outputPath}/temp/manifest.json', 'r', encoding='utf-8' f"{self.outputPath}/temp/manifest.json", "r", encoding="utf-8"
) as manifest: ) as manifest:
data = json.loads(manifest.read()) data = json.loads(manifest.read())
data['header'][ data["header"][
'description' "description"
] = f"the Player of the Music {self.midFileName}" ] = f"the Player of the Music {self.midFileName}"
data['header']['name'] = self.midFileName data["header"]["name"] = self.midFileName
data['header']['uuid'] = str(uuid.uuid4()) data["header"]["uuid"] = str(uuid.uuid4())
data['modules'][0]['description'] = 'None' data["modules"][0]["description"] = "None"
data['modules'][0]['uuid'] = str(uuid.uuid4()) data["modules"][0]["uuid"] = str(uuid.uuid4())
manifest.close() manifest.close()
open(f'{self.outputPath}/temp/manifest.json', 'w', encoding='utf-8').write( open(f"{self.outputPath}/temp/manifest.json", "w", encoding="utf-8").write(
json.dumps(data) json.dumps(data)
) )
# 将命令列表写入文件 # 将命令列表写入文件
indexfile = open( indexfile = open(
f'{self.outputPath}/temp/functions/index.mcfunction', 'w', encoding='utf-8' f"{self.outputPath}/temp/functions/index.mcfunction", "w", encoding="utf-8"
) )
for track in cmdlist: for track in cmdlist:
indexfile.write( indexfile.write(
'function mscplay/track' + str(cmdlist.index(track) + 1) + '\n' "function mscplay/track" + str(cmdlist.index(track) + 1) + "\n"
) )
with open( with open(
f'{self.outputPath}/temp/functions/mscplay/track{cmdlist.index(track)+1}.mcfunction', f"{self.outputPath}/temp/functions/mscplay/track{cmdlist.index(track) + 1}.mcfunction",
'w', "w",
encoding='utf-8', encoding="utf-8",
) as f: ) as f:
f.write('\n'.join(track)) f.write("\n".join(track))
indexfile.writelines( indexfile.writelines(
( (
'scoreboard players add @a[scores={' "scoreboard players add @a[scores={"
+ scoreboardname + scoreboardname
+ '=1..}] ' + "=1..}] "
+ scoreboardname + scoreboardname
+ ' 1\n', + " 1\n",
( (
'scoreboard players reset @a[scores={' "scoreboard players reset @a[scores={"
+ scoreboardname + scoreboardname
+ '=' + "="
+ str(maxscore + 20) + str(maxscore + 20)
+ '..}]' + "..}]"
+ f' {scoreboardname}\n' + f" {scoreboardname}\n"
) )
if isAutoReset if isAutoReset
else '', else "",
f'function mscplay/progressShow\n' if progressbar else '', f"function mscplay/progressShow\n" if progressbar else "",
) )
) )
if progressbar: if progressbar:
if progressbar == True: if progressbar == True:
with open( with open(
f'{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction', f"{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction",
'w', "w",
encoding='utf-8', encoding="utf-8",
) as f: ) as f:
f.writelines( f.writelines(
'\n'.join(self.__formProgressBar(maxscore, scoreboardname)) "\n".join(self.__formProgressBar(maxscore, scoreboardname))
) )
else: else:
with open( with open(
f'{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction', f"{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction",
'w', "w",
encoding='utf-8', encoding="utf-8",
) as f: ) as f:
f.writelines( f.writelines(
'\n'.join( "\n".join(
self.__formProgressBar( self.__formProgressBar(
maxscore, scoreboardname, progressbar maxscore, scoreboardname, progressbar
) )
@ -652,18 +759,18 @@ class midiConvert:
indexfile.close() indexfile.close()
makeZip( makeZip(
f'{self.outputPath}/temp/', self.outputPath + f'/{self.midFileName}.mcpack' f"{self.outputPath}/temp/", self.outputPath + f"/{self.midFileName}.mcpack"
) )
shutil.rmtree(f'{self.outputPath}/temp/') shutil.rmtree(f"{self.outputPath}/temp/")
def toBDXfile( def toBDXfile(
self, self,
method: int = 1, method: int = 1,
author: str = 'Eilles', author: str = "Eilles",
progressbar=False, progressbar=False,
maxheight: int = 64, maxheight: int = 64,
scoreboardname: str = 'mscplay', scoreboardname: str = "mscplay",
volume: float = 1.0, volume: float = 1.0,
speed: float = 1.0, speed: float = 1.0,
isAutoReset: bool = False, isAutoReset: bool = False,
@ -686,7 +793,7 @@ class midiConvert:
scoreboardname, volume, speed scoreboardname, volume, speed
) )
else: else:
return (False, f'无法找到算法ID {method} 对应的转换算法') return (False, f"无法找到算法ID {method} 对应的转换算法")
if not os.path.exists(self.outputPath): if not os.path.exists(self.outputPath):
os.makedirs(self.outputPath) os.makedirs(self.outputPath)
@ -705,10 +812,10 @@ class midiConvert:
"y": (b"\x11", b"\x10"), "y": (b"\x11", b"\x10"),
"z": (b"\x13", b"\x12"), "z": (b"\x13", b"\x12"),
} }
'''key存储了方块移动指令的数据其中可以用key[x|y|z][0|1]来表示xyz的减或增''' """key存储了方块移动指令的数据其中可以用key[x|y|z][0|1]来表示xyz的减或增"""
x = 'x' x = "x"
y = 'y' y = "y"
z = 'z' z = "z"
_sideLength = self.__fillSquareSideLength(totalcount, maxheight) _sideLength = self.__fillSquareSideLength(totalcount, maxheight)
@ -726,11 +833,11 @@ class midiConvert:
if isAutoReset: if isAutoReset:
commands += ( commands += (
'scoreboard players reset @a[scores={' "scoreboard players reset @a[scores={"
+ scoreboardname + scoreboardname
+ '=' + "="
+ str(maxScore + 20) + str(maxScore + 20)
+ '}] ' + "}] "
+ scoreboardname + scoreboardname
) )
@ -760,7 +867,7 @@ class midiConvert:
condition=False, condition=False,
needRedstone=False, needRedstone=False,
tickDelay=0, tickDelay=0,
customName='', customName="",
executeOnFirstTick=False, executeOnFirstTick=False,
trackOutput=True, trackOutput=True,
) )
@ -790,19 +897,19 @@ class midiConvert:
_bytes += key[y][int(yforward)] _bytes += key[y][int(yforward)]
with open(f"{self.outputPath}/{self.midFileName}.bdx", "ab+") as f: with open(f"{self.outputPath}/{self.midFileName}.bdx", "ab+") as f:
f.write(brotli.compress(_bytes + b'XE')) f.write(brotli.compress(_bytes + b"XE"))
return (True, _bytes, (nowx, maxheight, _sideLength)) return (True, _bytes, (nowx, maxheight, _sideLength))
def toBDXfile_withDelay( def toBDXfile_withDelay(
self, self,
method: int = 1, method: int = 1,
author: str = 'Eilles', author: str = "Eilles",
progressbar=False, progressbar=False,
maxheight: int = 64, maxheight: int = 64,
volume: float = 1.0, volume: float = 1.0,
speed: float = 1.0, speed: float = 1.0,
player: str = '@a', player: str = "@a",
): ):
""" """
使用method指定的转换算法将midi转换为BDX结构文件 使用method指定的转换算法将midi转换为BDX结构文件
@ -819,7 +926,7 @@ class midiConvert:
if method == 1: if method == 1:
cmdlist = self._toCmdList_withDelay_m1(volume, speed, player, progressbar) cmdlist = self._toCmdList_withDelay_m1(volume, speed, player, progressbar)
else: else:
return (False, f'无法找到算法ID {method} 对应的转换算法') return (False, f"无法找到算法ID {method} 对应的转换算法")
if not os.path.exists(self.outputPath): if not os.path.exists(self.outputPath):
os.makedirs(self.outputPath) os.makedirs(self.outputPath)
@ -838,10 +945,10 @@ class midiConvert:
"y": (b"\x11", b"\x10"), "y": (b"\x11", b"\x10"),
"z": (b"\x13", b"\x12"), "z": (b"\x13", b"\x12"),
} }
'''key存储了方块移动指令的数据其中可以用key[x|y|z][0|1]来表示xyz的减或增''' """key存储了方块移动指令的数据其中可以用key[x|y|z][0|1]来表示xyz的减或增"""
x = 'x' x = "x"
y = 'y' y = "y"
z = 'z' z = "z"
_sideLength = self.__fillSquareSideLength(len(cmdlist), maxheight) _sideLength = self.__fillSquareSideLength(len(cmdlist), maxheight)
@ -870,7 +977,7 @@ class midiConvert:
condition=False, condition=False,
needRedstone=False, needRedstone=False,
tickDelay=delay, tickDelay=delay,
customName='', customName="",
executeOnFirstTick=False, executeOnFirstTick=False,
trackOutput=True, trackOutput=True,
) )
@ -900,6 +1007,6 @@ class midiConvert:
_bytes += key[y][int(yforward)] _bytes += key[y][int(yforward)]
with open(f"{self.outputPath}/{self.midFileName}.bdx", "ab+") as f: with open(f"{self.outputPath}/{self.midFileName}.bdx", "ab+") as f:
f.write(brotli.compress(_bytes + b'XE')) f.write(brotli.compress(_bytes + b"XE"))
return (True, _bytes, (nowx, maxheight, _sideLength)) return (True, _bytes, (nowx, maxheight, _sideLength))

Binary file not shown.

28
msctPkgver/readXLSX.py Normal file
View File

@ -0,0 +1,28 @@
from openpyxl import *
def get():
wb = load_workbook('program音色表.xlsx')
ws = wb.active
# 所有行
keys = []
values = []
for row in ws.iter_rows():
for cell in row:
# print(cell.value)
try:
keys.append(int(cell.value))
except ValueError:
values.append(cell.value)
# # 所有列
# for column in ws.iter_cols():
# for cell in column:
# print(cell.value)
out = ""
index = 0
for i in keys:
out += ", \"" + str(i) + "\": \"" + values[index] + "\""
index += 1
print(out)