diff --git a/.gitignore b/.gitignore index d48cb25..a945659 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,6 @@ dmypy.json # Cython debug symbols cython_debug/ + +# Pycharm +/.idea diff --git a/README.md b/README.md index b15dde9..0029806 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ > > `pip install brotli` > +> `pip install openpyxl` +> > 3. 开始使用! > 在目录下打开cmd,进入到目录下,执行以下命令:(选择你需要的) > @@ -111,7 +113,8 @@ ## 致谢🙏 - 感谢 昀梦\ 找出指令生成错误bug并指正 -- 感谢由 Charlie_Ping “查理平” 带来的bdx文件转换参考 +- 感谢由 Charlie_Ping “查理平” 带来的bdx文件转换参考, +以及mid转我的世界乐器参考表格 - 感谢由 CMA_2401PT 为我们的软件开发进行指导 - 感谢由 Dislink Sforza \带来的midi音色解析以及转换指令的算法,我们将其加入了我们众多算法之一 - 感谢 Touch \提供的测试支持 diff --git a/README_EN.md b/README_EN.md index 054fb62..3617f60 100644 --- a/README_EN.md +++ b/README_EN.md @@ -66,6 +66,8 @@ A simple Python package. > > `pip install brotli` > +> `pip install openpyxl` +> > 3. Start using! > > 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. - *!! They have given me the rights to directly copy the lib into Musicreater* - Thank *昀梦*\ 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 *Miracle Plume “神羽”* \ for the Miracle Plume Bedrock Edition Audio Resource Pack - 感谢由 Dislink Sforza \带来的midi转换算法,我们将其加入了我们众多算法之一 diff --git a/example_convert_mcpack.py b/example_convert_mcpack.py index ece9943..7f3202f 100644 --- a/example_convert_mcpack.py +++ b/example_convert_mcpack.py @@ -13,3 +13,10 @@ convertion.tomcpack( float(input('请输入音量(0-1):')), 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) diff --git a/msctPkgver/main.py b/msctPkgver/main.py index c0758ec..011c1eb 100644 --- a/msctPkgver/main.py +++ b/msctPkgver/main.py @@ -33,6 +33,9 @@ Note! Except for this source file, all the files in this repository and this pro import os import mido import brotli +import json +import uuid +import shutil def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): @@ -45,7 +48,7 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): """ import zipfile - zipf = zipfile.ZipFile(outFilename, 'w', compression) + zipf = zipfile.ZipFile(outFilename, "w", compression) pre_len = len(os.path.dirname(sourceDir)) for parent, dirnames, filenames in os.walk(sourceDir): for filename in filenames: @@ -59,21 +62,21 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): class midiConvert: def __init__(self): - '''简单的midi转换类,将midi文件转换为我的世界结构或者包''' + """简单的midi转换类,将midi文件转换为我的世界结构或者包""" pass def convert(self, midiFile: str, outputPath: str): - '''转换前需要先运行此函数来获取基本信息''' + """转换前需要先运行此函数来获取基本信息""" self.midiFile = midiFile - '''midi文件路径''' + """midi文件路径""" self.midi = mido.MidiFile(self.midiFile) - '''MidiFile对象''' + """MidiFile对象""" self.outputPath = outputPath - '''输出路径''' + """输出路径""" # 将self.midiFile的文件名,不含路径且不含后缀存入self.midiFileName self.midFileName = os.path.splitext(os.path.basename(self.midiFile))[0] - '''文件名,不含路径且不含后缀''' + """文件名,不含路径且不含后缀""" def __Inst2soundIDwithX(self, instrumentID): """返回midi的乐器ID对应的我的世界乐器名,对于音域转换算法,如下: @@ -84,59 +87,159 @@ class midiConvert: 贝斯bass、迪吉里杜管didgeridoo的时候为8 长笛flute、牛铃cou_bell的时候为5 钟琴bell、管钟chime、木琴xylophone的时候为4 + 而存在一些打击乐器basedrum、hat、snare,没有音域,则没有X,那么我们返回7即可 :param instrumentID: midi的乐器ID :param default: 如果instrumentID不在范围内,返回的默认我的世界乐器名称 :return: (str我的世界乐器名, int转换算法中的X)""" - if instrumentID == 105: - return 'note.banjo', 6 - if instrumentID in range(32, 40): - return 'note.bass', 8 - if instrumentID in range(115, 119): - return 'note.basedrum', 7 # 注意,这里是底鼓,打击乐器无音域 - if instrumentID == 9 or instrumentID == 14: - return 'note.bell', 4 - if instrumentID == 80 or instrumentID == 81: - return 'note.bit', 6 - if instrumentID == 112: - return 'note.cow_bell', 5 - if instrumentID == -1: - return 'note.didgeridoo', 8 - if instrumentID in range(72, 80): - return 'note.flute', 5 - if instrumentID in range(24, 32): - return 'note.guitar', 7 - if instrumentID == -2: - return 'note.hat', 7 # 注意,这里是击鼓沿,打击乐器无音域 - if instrumentID == 14: - return 'note.chime', 4 - if instrumentID == 8 or instrumentID == 11: - return 'iron_xylophone', 6 - if instrumentID == 2: - return 'note.pling', 6 - if instrumentID == 114: - return 'note.snare', 7 # 注意,这里是小军鼓,打击乐器无音域 - if instrumentID == 13: - return 'note.xylophone', 4 - return 'note.harp', 6 + return { + 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", 7), # 打击乐器无音域 + 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.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): - 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( self, maxscore: int, scoreboardname: str, progressbar: tuple = ( - r'▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]', - ('§e=§r', '§7=§r'), + r"▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]", + ("§e=§r", "§7=§r"), ), ) -> list: pgsstyle = progressbar[0] - '''用于被替换的进度条原始样式''' + """用于被替换的进度条原始样式""" - ''' + """ | 标识符 | 指定的可变量 | |---------|----------------| | `%%N` | 乐曲名(即传入的文件名)| @@ -146,7 +249,7 @@ class midiConvert: | `%^t` | 曲目总时长 | | `%%%` | 当前进度比率 | | `_` | 用以表示进度条占位| - ''' + """ def __replace( s: str, tobeReplaced: str, replaceWith: str, times: int, other: str @@ -155,7 +258,7 @@ class midiConvert: return s.replace(tobeReplaced, other) if times == s.count(tobeReplaced): return s.replace(tobeReplaced, replaceWith) - result = '' + result = "" t = 0 for i in s: if i == tobeReplaced: @@ -170,12 +273,12 @@ class midiConvert: return result idlist = { - r'%%N': self.midFileName, - r'%%s': r'%%s', - r'%^s': str(maxscore), - r'%%t': r'%%t', - r'%^t': self.__score2time(maxscore), - r'%%%': r'%%%', + r"%%N": self.midFileName, + r"%%s": r"%%s", + r"%^s": str(maxscore), + r"%%t": r"%%t", + r"%^t": self.__score2time(maxscore), + r"%%%": r"%%%", } ids = {} @@ -192,32 +295,32 @@ class midiConvert: del idlist - pgblength = pgsstyle.count('_') - '''进度条的“条”长度''' + pgblength = pgsstyle.count("_") + """进度条的“条”长度""" finalprgsbar = [] for i in range(maxscore): nowstr = pgsstyle - if ids[r'%%s'] == True: - nowstr = nowstr.replace(r'%%s', str(i + 1)) - if ids[r'%%t'] == True: - nowstr = nowstr.replace(r'%%t', self.__score2time(i + 1)) - if ids[r'%%%'] == True: + if ids[r"%%s"] == True: + nowstr = nowstr.replace(r"%%s", str(i + 1)) + if ids[r"%%t"] == True: + nowstr = nowstr.replace(r"%%t", self.__score2time(i + 1)) + if ids[r"%%%"] == True: 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) finalprgsbar.append( - 'title @a[scores={' + "title @a[scores={" + scoreboardname - + '=' + + "=" + str(i + 1) - + '}] actionbar ' + + "}] actionbar " + __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, needRedstone: bool = True, tickDelay: int = 0, - customName: str = '', + customName: str = "", executeOnFirstTick: bool = False, trackOutput: bool = True, ): @@ -285,7 +388,7 @@ class midiConvert: impluse.to_bytes(4, byteorder="big", signed=False), bytes(command, 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), executeOnFirstTick.to_bytes(1, byteorder="big"), trackOutput.to_bytes(1, byteorder="big"), @@ -296,7 +399,7 @@ class midiConvert: return block 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: """ 使用Dislink Sforza的转换思路,将midi转换为我的世界命令列表 @@ -322,13 +425,15 @@ class midiConvert: for msg in track: ticks += msg.time + # print(msg) if msg.is_meta: - if msg.type == 'set_tempo': + if msg.type == "set_tempo": tempo = msg.tempo - if msg.type == 'program_change': - instrumentID = msg.program 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( (ticks * tempo) / ((self.midi.ticks_per_beat * float(speed)) * 50000) @@ -336,12 +441,12 @@ class midiConvert: maxscore = max(maxscore, nowscore) soundID, _X = self.__Inst2soundIDwithX(instrumentID) singleTrack.append( - 'execute @a[scores={' + "execute @a[scores={" + str(scoreboardname) - + '=' + + "=" + 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 if len(singleTrack) != 0: @@ -353,7 +458,7 @@ class midiConvert: self, volume: float = 1.0, speed: float = 1.0, - player: str = '@a', + player: str = "@a", isMixedWithPrograssBar=False, ) -> list: """ @@ -373,8 +478,8 @@ class midiConvert: if isMixedWithPrograssBar == True: isMixedWithPrograssBar = ( - r'▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]', - ('§e=§r', '§7=§r'), + r"▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]", + ("§e=§r", "§7=§r"), ) for i, track in enumerate(self.midi.tracks): @@ -385,12 +490,12 @@ class midiConvert: for msg in track: ticks += msg.time if msg.is_meta: - if msg.type == 'set_tempo': + if msg.type == "set_tempo": tempo = msg.tempo - if msg.type == 'program_change': - instrumentID = msg.program 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( (ticks * tempo) / ((self.midi.ticks_per_beat * float(speed)) * 50000) @@ -398,11 +503,11 @@ class midiConvert: soundID, _X = self.__Inst2soundIDwithX(instrumentID) try: 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: 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()) @@ -410,9 +515,9 @@ class midiConvert: if isMixedWithPrograssBar: pgsstyle = isMixedWithPrograssBar[0] - '''用于被替换的进度条原始样式''' + """用于被替换的进度条原始样式""" - ''' + """ | 标识符 | 指定的可变量 | |---------|----------------| | `%%N` | 乐曲名(即传入的文件名)| @@ -422,7 +527,7 @@ class midiConvert: | `%^t` | 曲目总时长 | | `%%%` | 当前进度比率 | | `_` | 用以表示进度条占位| - ''' + """ def __replace( s: str, tobeReplaced: str, replaceWith: str, times: int, other: str @@ -431,7 +536,7 @@ class midiConvert: return s.replace(tobeReplaced, other) if times == s.count(tobeReplaced): return s.replace(tobeReplaced, replaceWith) - result = '' + result = "" t = 0 for i in s: if i == tobeReplaced: @@ -446,12 +551,12 @@ class midiConvert: return result idlist = { - r'%%N': self.midFileName, - r'%%s': r'%%s', - r'%^s': str(allticks[-1]), - r'%%t': r'%%t', - r'%^t': self.__score2time(allticks[-1]), - r'%%%': r'%%%', + r"%%N": self.midFileName, + r"%%s": r"%%s", + r"%^s": str(allticks[-1]), + r"%%t": r"%%t", + r"%^t": self.__score2time(allticks[-1]), + r"%%%": r"%%%", } ids = {} @@ -468,8 +573,8 @@ class midiConvert: del idlist - pgblength = pgsstyle.count('_') - '''进度条的“条”长度''' + pgblength = pgsstyle.count("_") + """进度条的“条”长度""" results = [] @@ -489,34 +594,40 @@ class midiConvert: if isMixedWithPrograssBar: nowstr = pgsstyle - if ids[r'%%s'] == True: - nowstr = nowstr.replace(r'%%s', str(allticks[i] + 1)) - if ids[r'%%t'] == True: - nowstr = nowstr.replace(r'%%t', self.__score2time(allticks[i] + 1)) - if ids[r'%%%'] == True: + if ids[r"%%s"] == True: + nowstr = nowstr.replace(r"%%s", str(allticks[i] + 1)) + if ids[r"%%t"] == True: + nowstr = nowstr.replace(r"%%t", self.__score2time(allticks[i] + 1)) + if ids[r"%%%"] == True: 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) titlenow = __replace( nowstr, - '_', + "_", isMixedWithPrograssBar[1][0], countof_s, isMixedWithPrograssBar[1][1], ) - results.append((f'title {player} actionbar {titlenow}', 0,)) + results.append( + ( + f"title {player} actionbar {titlenow}", + 0, + ) + ) return results def __fillSquareSideLength(self, total: int, maxHeight: int): - '''给定总方块数量和最大高度,返回所构成的图形外切正方形的边长 + """给定总方块数量和最大高度,返回所构成的图形外切正方形的边长 :param total: 总方块数量 :param maxHeight: 最大高度 - :return: 外切正方形的边长 int''' + :return: 外切正方形的边长 int""" import math return math.ceil(math.sqrt(math.ceil(total / maxHeight))) @@ -526,7 +637,7 @@ class midiConvert: method: int = 1, isAutoReset: bool = False, progressbar=None, - scoreboardname: str = 'mscplay', + scoreboardname: str = "mscplay", volume: float = 1.0, speed: float = 1.0, ) -> bool: @@ -543,106 +654,102 @@ class midiConvert: if method == 1: cmdlist, _a, maxscore = self._toCmdList_m1(scoreboardname, volume, speed) else: - return (False, f'无法找到算法ID{method}对应的转换算法') + return (False, f"无法找到算法ID{method}对应的转换算法") del _a - import json - import uuid - import shutil - # 当文件f夹{self.outputPath}/temp/functions存在时清空其下所有项目,若其不存在则创建 - if os.path.exists(f'{self.outputPath}/temp/functions/'): - shutil.rmtree(f'{self.outputPath}/temp/functions/') - os.makedirs(f'{self.outputPath}/temp/functions/mscplay') + if os.path.exists(f"{self.outputPath}/temp/functions/"): + shutil.rmtree(f"{self.outputPath}/temp/functions/") + os.makedirs(f"{self.outputPath}/temp/functions/mscplay") # 写入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( - f"{self.outputPath}/temp/manifest.json", "w", encoding='utf-8' + f"{self.outputPath}/temp/manifest.json", "w", encoding="utf-8" ) as f: f.write( - "{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + '{\n "format_version": 1,\n "header": {\n "description": "' + self.midFileName - + " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" + + ' Pack : behavior pack",\n "version": [ 0, 0, 1 ],\n "name": "' + self.midFileName - + "Pack\",\n \"uuid\": \"" + + 'Pack",\n "uuid": "' + str(uuid.uuid4()) - + "\"\n },\n \"modules\": [\n {\n \"description\": \"" + + '"\n },\n "modules": [\n {\n "description": "' + 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()) - + "\"\n }\n ]\n}" + + '"\n }\n ]\n}' ) else: with open( - f'{self.outputPath}/temp/manifest.json', 'r', encoding='utf-8' + f"{self.outputPath}/temp/manifest.json", "r", encoding="utf-8" ) as manifest: data = json.loads(manifest.read()) - data['header'][ - 'description' + data["header"][ + "description" ] = f"the Player of the Music {self.midFileName}" - data['header']['name'] = self.midFileName - data['header']['uuid'] = str(uuid.uuid4()) - data['modules'][0]['description'] = 'None' - data['modules'][0]['uuid'] = str(uuid.uuid4()) + data["header"]["name"] = self.midFileName + data["header"]["uuid"] = str(uuid.uuid4()) + data["modules"][0]["description"] = "None" + data["modules"][0]["uuid"] = str(uuid.uuid4()) 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) ) # 将命令列表写入文件 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: indexfile.write( - 'function mscplay/track' + str(cmdlist.index(track) + 1) + '\n' + "function mscplay/track" + str(cmdlist.index(track) + 1) + "\n" ) with open( - f'{self.outputPath}/temp/functions/mscplay/track{cmdlist.index(track)+1}.mcfunction', - 'w', - encoding='utf-8', + f"{self.outputPath}/temp/functions/mscplay/track{cmdlist.index(track) + 1}.mcfunction", + "w", + encoding="utf-8", ) as f: - f.write('\n'.join(track)) + f.write("\n".join(track)) indexfile.writelines( ( - 'scoreboard players add @a[scores={' + "scoreboard players add @a[scores={" + scoreboardname - + '=1..}] ' + + "=1..}] " + scoreboardname - + ' 1\n', + + " 1\n", ( - 'scoreboard players reset @a[scores={' + "scoreboard players reset @a[scores={" + scoreboardname - + '=' + + "=" + str(maxscore + 20) - + '..}]' - + f' {scoreboardname}\n' + + "..}]" + + f" {scoreboardname}\n" ) if isAutoReset - else '', - f'function mscplay/progressShow\n' if progressbar else '', + else "", + f"function mscplay/progressShow\n" if progressbar else "", ) ) if progressbar: if progressbar == True: with open( - f'{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction', - 'w', - encoding='utf-8', + f"{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction", + "w", + encoding="utf-8", ) as f: f.writelines( - '\n'.join(self.__formProgressBar(maxscore, scoreboardname)) + "\n".join(self.__formProgressBar(maxscore, scoreboardname)) ) else: with open( - f'{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction', - 'w', - encoding='utf-8', + f"{self.outputPath}/temp/functions/mscplay/progressShow.mcfunction", + "w", + encoding="utf-8", ) as f: f.writelines( - '\n'.join( + "\n".join( self.__formProgressBar( maxscore, scoreboardname, progressbar ) @@ -652,18 +759,18 @@ class midiConvert: indexfile.close() 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( self, method: int = 1, - author: str = 'Eilles', + author: str = "Eilles", progressbar=False, maxheight: int = 64, - scoreboardname: str = 'mscplay', + scoreboardname: str = "mscplay", volume: float = 1.0, speed: float = 1.0, isAutoReset: bool = False, @@ -686,7 +793,7 @@ class midiConvert: scoreboardname, volume, speed ) else: - return (False, f'无法找到算法ID {method} 对应的转换算法') + return (False, f"无法找到算法ID {method} 对应的转换算法") if not os.path.exists(self.outputPath): os.makedirs(self.outputPath) @@ -705,10 +812,10 @@ class midiConvert: "y": (b"\x11", b"\x10"), "z": (b"\x13", b"\x12"), } - '''key存储了方块移动指令的数据,其中可以用key[x|y|z][0|1]来表示xyz的减或增''' - x = 'x' - y = 'y' - z = 'z' + """key存储了方块移动指令的数据,其中可以用key[x|y|z][0|1]来表示xyz的减或增""" + x = "x" + y = "y" + z = "z" _sideLength = self.__fillSquareSideLength(totalcount, maxheight) @@ -726,11 +833,11 @@ class midiConvert: if isAutoReset: commands += ( - 'scoreboard players reset @a[scores={' + "scoreboard players reset @a[scores={" + scoreboardname - + '=' + + "=" + str(maxScore + 20) - + '}] ' + + "}] " + scoreboardname ) @@ -760,7 +867,7 @@ class midiConvert: condition=False, needRedstone=False, tickDelay=0, - customName='', + customName="", executeOnFirstTick=False, trackOutput=True, ) @@ -790,19 +897,19 @@ class midiConvert: _bytes += key[y][int(yforward)] 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)) def toBDXfile_withDelay( self, method: int = 1, - author: str = 'Eilles', + author: str = "Eilles", progressbar=False, maxheight: int = 64, volume: float = 1.0, speed: float = 1.0, - player: str = '@a', + player: str = "@a", ): """ 使用method指定的转换算法,将midi转换为BDX结构文件 @@ -819,7 +926,7 @@ class midiConvert: if method == 1: cmdlist = self._toCmdList_withDelay_m1(volume, speed, player, progressbar) else: - return (False, f'无法找到算法ID {method} 对应的转换算法') + return (False, f"无法找到算法ID {method} 对应的转换算法") if not os.path.exists(self.outputPath): os.makedirs(self.outputPath) @@ -838,10 +945,10 @@ class midiConvert: "y": (b"\x11", b"\x10"), "z": (b"\x13", b"\x12"), } - '''key存储了方块移动指令的数据,其中可以用key[x|y|z][0|1]来表示xyz的减或增''' - x = 'x' - y = 'y' - z = 'z' + """key存储了方块移动指令的数据,其中可以用key[x|y|z][0|1]来表示xyz的减或增""" + x = "x" + y = "y" + z = "z" _sideLength = self.__fillSquareSideLength(len(cmdlist), maxheight) @@ -870,7 +977,7 @@ class midiConvert: condition=False, needRedstone=False, tickDelay=delay, - customName='', + customName="", executeOnFirstTick=False, trackOutput=True, ) @@ -900,6 +1007,6 @@ class midiConvert: _bytes += key[y][int(yforward)] 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)) diff --git a/msctPkgver/program音色表.xlsx b/msctPkgver/program音色表.xlsx new file mode 100644 index 0000000..b68bcf6 Binary files /dev/null and b/msctPkgver/program音色表.xlsx differ diff --git a/msctPkgver/readXLSX.py b/msctPkgver/readXLSX.py new file mode 100644 index 0000000..c5bb33f --- /dev/null +++ b/msctPkgver/readXLSX.py @@ -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)