diff --git a/.gitignore b/.gitignore index e98820f..acc23ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,18 @@ +# sth. can't open +/msctPkgver/secrets/*.py +/msctPkgver/secrets/*.c + + # mystuff /.vscode *.mid *.midi -# Byte-compiled / optimized / DLL files +# Byte-compiled / optimized __pycache__/ -*.py[cod] +*.pyc *$py.class -# C extensions -*.so - # Distribution / packaging .Python build/ diff --git a/LICENSE.md b/LICENSE.md index 2f4d5ce..c8abe70 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,20 +1,22 @@ - - **注意,以下条款或版权声明应当且必须是高于此项目中任何其他声明的** -1. 音·创的全部开发者享有其完整版权,开发者可以在任一时刻终止以后音·创源代码开放,若经由开发者授予特殊权利,则授权对象可以将源代码进行特定的被特殊授权的操作 -2. 除部分代码特殊声明外,音·创允许对其进行商业化使用,但是需要经过音·创主要开发者(诸葛亮与八卦阵、金羿)的一致授权,同时,授权对象在商业化授权的使用过程中必须依照Apache2.0协议 -3. 若存在对于音·创包含的部分代码的特殊开源声明,则此部分代码依照其特定的开源方式授权,但若此部分代码经由此部分代码的主要开发者一致特殊授权后商用,则授权对象在商用时依照此部分的开发者所准许的方式(或条款)进行商用,或默认依照Apache2.0协议进行商业化使用 -4. Apache2.0 协议的英文原文副本可见下文 +1. 音·创的全部开发者享有其完整版权,其开发者可以在任一时刻终止以后音·创源代码开放,若经由其开发者授予特殊权利,则授权对象可以将源代码进行特定的被特殊授权的操作 +2. 音·创或(及)其代码允许在 Apache2.0 协议的条款与说明下进行非商业使用 +3. 除部分代码特殊声明外,音·创允许对其或(及)其代码进行商业化使用,但是需要经过音·创主要开发者(诸葛亮与八卦阵、金羿)的一致授权,同时,授权对象在商业化授权的使用过程中必须依照 Apache2.0 协议的条款与说明 +4. 若存在对于音·创包含的部分代码的特殊开源声明,则此部分代码依照其特定的开源方式授权,但若此部分代码经由此部分代码的主要开发者一致特殊授权后商用,则授权对象在商用时依照此部分的开发者所准许的方式(或条款)进行商用,或默认依照 Apache2.0 协议进行商业化使用 +5. Apache2.0 协议的英文原文副本可见下文 > The English Translation of the TERMS AND CONDITIONS above is listed below +> > This translated version is for reference only and has no legal effect. +> > The version with legal effect is the Chinese version above. **Note, The TERMS AND CONDITIONS below should and must be above all others in this project** 1. *Musicreater* is fully copyrighted by all its developers, the developers have the right to make *Musicreater* close sourced at any time. Operations are permitted under specific terms instructed by its developer(s). -2. Commercial use of *Musicreater* is permitted under Apache License 2.0 with the unanimous permission of the steering developers of *Musicreater* (*bgArray*诸葛亮与八卦阵 and *Eilles*金羿). +2. Non-commercial use of *Musicreater* and(or) its source code is permitted under Apache License 2.0. +3. Commercial use of *Musicreater* is permitted under Apache License 2.0 with the unanimous permission of the steering developers of *Musicreater* (*bgArray*诸葛亮与八卦阵 and *Eilles*金羿). 4. *Musicreater* is open sourced under priority given: 1. License granted by the core developer(s) of a section after negotiation. 2. Explicitly stated license. diff --git a/demo_convert.py b/demo_convert.py index b41d3b5..c0fafbd 100644 --- a/demo_convert.py +++ b/demo_convert.py @@ -4,21 +4,17 @@ # 音·创 开发交流群 861684859 # Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") -# 若需转载或借鉴 请依照 Apache 2.0 许可证进行许可 +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md """ 音·创 库版 MIDI转换展示程序 Musicreater Package Version : Demo for Midi Conversion - Copyright 2022 all the developers of Musicreater - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Copyright 2023 all the developers of Musicreater +开源相关声明请见 ./Lisence.md +Terms & Conditions: ./Lisence.md """ from msctPkgver.main import * @@ -98,7 +94,8 @@ while True: - +m = 1 +'''采用的算法编号''' if os.path.isdir(midipath): @@ -107,8 +104,8 @@ if os.path.isdir(midipath): print(f'正在操作{i}') convertion.convert(midipath + '/' + i, outpath + '/' + i[:-4]) if outFormat == 0: - convertion.tomcpack( - 1, + print(convertion.tomcpack( + m, isAutoReset if isAutoReset != '' else bool(int(input('是否自动重置计分板(1|0):'))), @@ -116,10 +113,10 @@ if os.path.isdir(midipath): sbname if sbname != '' else input('请输入计分板名称:'), volume if volume != '' else float(input('请输入音量(0-1):')), speed if speed != '' else float(input('请输入速度倍率:')), - ) + )) elif outFormat == 1: - convertion.toBDXfile( - 1, + print(convertion.toBDXfile( + m, author if author != '' else input('请输入作者:'), isProgress, maxHeight if maxHeight != '' else int(input('请输入指令结构最大生成高度:')), @@ -129,21 +126,21 @@ if os.path.isdir(midipath): isAutoReset if isAutoReset != '' else bool(int(input('是否自动重置计分板(1|0):'))), - ) + )) else: convertion.convert(midipath, outpath) if outFormat == 0: - convertion.tomcpack( - 1, + print(convertion.tomcpack( + m, isAutoReset if isAutoReset != '' else bool(int(input('是否自动重置计分板(1|0):'))), isProgress, sbname if sbname != '' else input('请输入计分板名称:'), volume if volume != '' else float(input('请输入音量(0-1):')), speed if speed != '' else float(input('请输入速度倍率:')), - ) + )) elif outFormat == 1: - convertion.toBDXfile( - 1, + print(convertion.toBDXfile( + m, author if author != '' else input('请输入作者:'), isProgress, maxHeight if maxHeight != '' else int(input('请输入指令结构最大生成高度:')), @@ -151,4 +148,4 @@ else: volume if volume != '' else float(input('请输入音量(0-1):')), speed if speed != '' else float(input('请输入速度倍率:')), isAutoReset if isAutoReset != '' else bool(int(input('是否自动重置计分板(1|0):'))), - ) + )) diff --git a/demo_convert_bdx_byDelay.py b/demo_convert_bdx_byDelay.py index 4e4b5b4..13f47dc 100644 --- a/demo_convert_bdx_byDelay.py +++ b/demo_convert_bdx_byDelay.py @@ -1,5 +1,22 @@ +# -*- coding: utf-8 -*- + # THIS PROGRAM IS ONLY A TEST EXAMPLE +# 音·创 开发交流群 861684859 +# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com +# 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md + + +""" +音·创 库版 MIDI转换展示程序 +Musicreater Package Version : Demo for Midi Conversion + +Copyright 2023 all the developers of Musicreater + +开源相关声明请见 ./Lisence.md +Terms & Conditions: ./Lisence.md +""" from msctPkgver.main import * diff --git a/magicDemo.py b/magicDemo.py index aeef655..6a7c239 100644 --- a/magicDemo.py +++ b/magicDemo.py @@ -4,22 +4,17 @@ # 音·创 开发交流群 861684859 # Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") -# 若需转载或借鉴 请依照 Apache 2.0 许可证进行许可 +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md """ 音·创 库版 MIDI转换示例程序 Musicreater Package Version : Demo for Midi Conversion - Copyright 2022 all the developers of Musicreater - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - +Copyright 2023 all the developers of Musicreater +开源相关声明请见 ./Lisence.md +Terms & Conditions: ./Lisence.md """ languages = { @@ -52,7 +47,7 @@ languages = { "Re-Enter": "请重新输入", "Dealing": "正在处理", "FileNotFound": "文件(夹)不存在", - "ChooseOutPath": "请输入输出路径", + "ChooseOutPath": "请输入结果输出路径", "EnterSelecter": "请输入播放者选择器", "Saying": "言·论", } @@ -267,19 +262,24 @@ def ipt( return MainConsole.input("", password=password, stream=stream) -def formatipt(notice: str, fun: function, errnote: str): +def formatipt(notice: str, fun, errnote: str = "", *extraArg): + '''循环输入,以某种格式 + notice: 输入时的提示 + fun: 格式函数 + errnote: 输入不符格式时的提示 + *extraArg: 对于函数的其他参数''' while True: result = ipt(notice) try: - result = fun(result) + funresult = fun(result, *extraArg) break except: prt(errnote) continue - return result - + return result, funresult +# 获取midi列表 while True: midipath = ipt(f"{_('ChoosePath')}{_(':')}").lower() if os.path.exists(midipath): @@ -301,7 +301,15 @@ while True: continue break +# 获取输出地址 +outpath = formatipt( + f"{_('ChooseOutPath')}{_(':')}", + os.path.exists, + f"{_('FileNotFound')}{_(',')}{_('Re-Enter')}{_('.')}", +).lower() + +# 选择输出格式 while True: fileFormat = ipt(f"{_('ChooseFileFormat')}{_(':')}").lower() if fileFormat in ('0', 'mcpack'): @@ -309,7 +317,7 @@ while True: prt(_("EnterArgs")) if len(midis) > 1: prt(_("noteofArgs")) - + elif fileFormat in ('1', 'bdx'): fileFormat = 1 while True: diff --git a/msctPkgver/__init__.py b/msctPkgver/__init__.py index ecc3ff1..41c8a17 100644 --- a/msctPkgver/__init__.py +++ b/msctPkgver/__init__.py @@ -4,29 +4,23 @@ # 音·创 开发交流群 861684859 # Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") -# 若需转载或借鉴 请依照 Apache 2.0 许可证进行许可 +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md -__version__ = '0.0.1' +__version__ = '0.1.0' __all__ = [] __author__ = (('金羿', 'Eilles Wan'), ('诸葛亮与八卦阵', 'bgArray'), ('鸣凤鸽子', 'MingFengPigeon')) """ 音·创 库版 (Musicreater Package Version) 是一款免费开源的针对《我的世界:基岩版》的midi音乐转换库 -注意!除了此源文件以外,任何属于此仓库以及此项目的文件均依照Apache许可证进行许可 Musicreater pkgver (Package Version 音·创 库版) A free open source library used for convert midi file into formats that is suitable for **Minecraft: Bedrock Edition**. -Note! Except for this source file, all the files in this repository and this project are licensed under Apache License 2.0 - Copyright © 2022 all the developers of Musicreater - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Copyright 2023 all the developers of Musicreater +开源相关声明请见 ../Lisence.md +Terms & Conditions: ../Lisence.md """ diff --git a/msctPkgver/exceptions.py b/msctPkgver/exceptions.py index 23ec562..dfddf46 100644 --- a/msctPkgver/exceptions.py +++ b/msctPkgver/exceptions.py @@ -4,30 +4,19 @@ # 音·创 开发交流群 861684859 # Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") -# 若需使用或借鉴 请依照 Apache 2.0 许可证进行许可 +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md """ 音·创 库版 (Musicreater Package Version) 是一款免费开源的针对《我的世界:基岩版》的midi音乐转换库 -注意!除了此源文件以外,任何属于此仓库以及此项目的文件均依照Apache许可证进行许可 Musicreater pkgver (Package Version 音·创 库版) A free open source library used for convert midi file into formats that is suitable for **Minecraft: Bedrock Edition**. -Note! Except for this source file, all the files in this repository and this project are licensed under Apache License 2.0 - Copyright 2022 all the developers of Musicreater +Copyright 2023 all the developers of Musicreater - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +开源相关声明请见 ../Lisence.md +Terms & Conditions: ../Lisence.md """ diff --git a/msctPkgver/main.py b/msctPkgver/main.py index bcdbe23..a69ea23 100644 --- a/msctPkgver/main.py +++ b/msctPkgver/main.py @@ -4,25 +4,19 @@ # 音·创 开发交流群 861684859 # Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") -# 若需使用或借鉴 请依照 Apache 2.0 许可证进行许可 +# 若需转载或借鉴 许可声明请查看仓库目录下的 Lisence.md """ 音·创 库版 (Musicreater Package Version) 是一款免费开源的针对《我的世界:基岩版》的midi音乐转换库 -注意!包括此源文件,任何属于此仓库以及此项目的文件均依照Apache许可证进行许可 Musicreater pkgver (Package Version 音·创 库版) A free open source library used for convert midi file into formats that is suitable for **Minecraft: Bedrock Edition**. -Note! Including this source file, all the files in this repository and this project are licensed under Apache License 2.0 - Copyright 2022 all the developers of Musicreater - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Copyright 2023 all the developers of Musicreater +开源相关声明请见 ../Lisence.md +Terms & Conditions: ../Lisence.md """ import os @@ -59,7 +53,9 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): class SingleNote: - def __init__(self, instrument: int, pitch: int, velocity, startTime, lastTime): + def __init__( + self, instrument: int, pitch: int, velocity, startTime: int, lastTime: int + ): """用于存储单个音符的类 :param instrument 乐器编号 :param pitch 音符编号 @@ -68,17 +64,24 @@ class SingleNote: 注:此处的时间是用从乐曲开始到当前的毫秒数 :param lastTime 音符延续时间(ms)""" self.instrument = instrument + '''乐器编号''' self.note = pitch + '''音符编号''' self.velocity = velocity + '''力度/响度''' self.startTime = startTime + '''开始之时 ms''' self.lastTime = lastTime + '''音符持续时间 ms''' @property def inst(self): + '''乐器编号''' return self.instrument @property def pitch(self): + '''音符编号''' return self.note def __str__(self): @@ -310,23 +313,82 @@ class midiConvert: a = ("note.flute", 5) return a - def __bitInst2IDwithX(self, instrumentID:int): - # 感谢Dislink的网页转换页面的代码给我抄 - return ("note.bd", 7) - - + def __bitInst2IDwithX(self, instrumentID): + try: + try: + return { + 34: ('note.bd', 7), + 35: ('note.bd', 7), + 36: ('note.hat', 7), + 37: ('note.snare', 7), + 38: ('note.snare', 7), + 39: ('note.snare', 7), + 40: ('note.hat', 7), + 41: ('note.snare', 7), + 42: ('note.hat', 7), + 43: ('note.snare', 7), + 44: ('note.snare', 7), + 45: ('note.bell', 4), + 46: ('note.snare', 7), + 47: ('note.snare', 7), + 48: ('note.bell', 4), + 49: ('note.hat', 7), + 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), + 58: ('note.chime', 4), + 59: ('note.iron_xylophone', 6), + 60: ('note.bd', 7), + 61: ('note.bd', 7), + 62: ('note.xylophone', 4), + 63: ('note.xylophone', 4), + 64: ('note.xylophone', 4), + 65: ('note.hat', 7), + 66: ('note.bell', 4), + 67: ('note.bell', 4), + 68: ('note.hat', 7), + 69: ('note.hat', 7), + 70: ('note.flute', 5), + 71: ('note.flute', 5), + 72: ('note.hat', 7), + 73: ('note.hat', 7), + 74: ('note.xylophone', 4), + 75: ('note.hat', 7), + 76: ('note.hat', 7), + 77: ('note.xylophone', 4), + 78: ('note.xylophone', 4), + 79: ('note.bell', 4), + 80: ('note.bell', 4), + }[instrumentID] + except: + return ("note.bd", 7) + except: + print("WARN", "无法导入打击乐器列表动态链接库,可能是不支持当前及其环境,打击乐器使用Dislink算法代替。") + if instrumentID == 55: + return ("note.cow_bell", 5) + elif instrumentID in [41, 43, 45]: + return ("note.hat", 7) + elif instrumentID in [36, 37, 39]: + return ("note.snare", 7) + else: + return ("note.bd", 7) def __score2time(self, score: int): 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"), - ), + self, + maxscore: int, + scoreboardname: str, + progressbar: tuple = ( + r"▶ %%N [ %%s/%^s %%% __________ %%t|%^t ]", + ("§e=§r", "§7=§r"), + ), ) -> list: pgsstyle = progressbar[0] @@ -345,7 +407,7 @@ class midiConvert: """ def __replace( - s: str, tobeReplaced: str, replaceWith: str, times: int, other: str + s: str, tobeReplaced: str, replaceWith: str, times: int, other: str ): if times == 0: return s.replace(tobeReplaced, other) @@ -420,16 +482,16 @@ class midiConvert: return finalprgsbar def __formCMDblk( - self, - command: str, - particularValue: int, - impluse: int = 0, - condition: bool = False, - needRedstone: bool = True, - tickDelay: int = 0, - customName: str = "", - executeOnFirstTick: bool = False, - trackOutput: bool = True, + self, + command: str, + particularValue: int, + impluse: int = 0, + condition: bool = False, + needRedstone: bool = True, + tickDelay: int = 0, + customName: str = "", + executeOnFirstTick: bool = False, + trackOutput: bool = True, ): """ 使用指定项目返回指定的指令方块放置指令项 @@ -492,7 +554,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转换为我的世界命令列表 @@ -534,7 +596,10 @@ class midiConvert: except NameError: raise NotDefineTempoError("计算当前分数时出错 未定义参量 Tempo") maxscore = max(maxscore, nowscore) - soundID, _X = self.__Inst2soundIDwithX(instrumentID) + if msg.channel == 9: + soundID, _X = self.__bitInst2IDwithX(instrumentID) + else: + soundID, _X = self.__Inst2soundIDwithX(instrumentID) # /playsound [player: target] [position: x y z] # [volume: float] [pitch: float] [minimumVolume: float] @@ -554,7 +619,7 @@ class midiConvert: + str(nowscore) + "}" + f"] ~ ~ ~ playsound {soundID} @s ~ ~{1 / volume - 1} ~ " - f"{msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}" + f"{msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}" ) commands += 1 if len(singleTrack) != 0: @@ -563,12 +628,11 @@ class midiConvert: return [tracks, commands, maxscore] # 原本这个算法的转换效果应该和上面的算法相似的 - # 但不好意思 我增加了泛音功能 def _toCmdList_m2( - self, - scoreboardname: str = "mscplay", - MaxVolume: float = 1.0, - speed: float = 1.0, + self, + scoreboardname: str = "mscplay", + MaxVolume: float = 1.0, + speed: float = 1.0, ) -> list: """ 使用金羿的转换思路,将midi转换为我的世界命令列表 @@ -624,7 +688,7 @@ class midiConvert: ) elif (msg.type == "note_on" and msg.velocity == 0) or ( - msg.type == "note_off" + msg.type == "note_off" ): channels[msg.channel].append(("NoteE", msg.note, microseconds)) @@ -656,6 +720,7 @@ class midiConvert: if channels.index(track) == 0: CheckFirstChannel = True + SpecialBits = False elif channels.index(track) == 9: SpecialBits = True else: @@ -670,7 +735,7 @@ class midiConvert: InstID = msg[1] elif msg[0] == "NoteS": - + if SpecialBits: soundID, _X = self.__bitInst2IDwithX(InstID) else: @@ -693,19 +758,15 @@ class midiConvert: return [tracks, cmdAmount, maxScore] - # 这才是加了线性插值的算法 - # 此算法有巨大问题 - # 暂时无法使用 - # 已经经过验证 需要再次修改 - # 等一段时间后我来通知 + # 简单的单音填充 def _toCmdList_m3( - self, - scoreboardname: str = "mscplay", - MaxVolume: float = 1.0, - speed: float = 1.0, + self, + scoreboardname: str = "mscplay", + MaxVolume: float = 1.0, + speed: float = 1.0, ) -> list: """ - 使用金羿的转换思路,将midi转换为我的世界命令列表,并使用线性插值算法优化音量 + 使用金羿的转换思路,将midi转换为我的世界命令列表,并使用完全填充算法优化音感 :param scoreboardname: 我的世界的计分板名称 :param MaxVolume: 音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频 :param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed @@ -758,7 +819,7 @@ class midiConvert: ) elif (msg.type == "note_on" and msg.velocity == 0) or ( - msg.type == "note_off" + msg.type == "note_off" ): channels[msg.channel].append(("NoteE", msg.note, microseconds)) @@ -822,11 +883,18 @@ class midiConvert: result = [] - totalCount = int(note.lastTime / 500000) + totalCount = int(note.lastTime / 500) for i in range(totalCount): - result.append((note.startTime + i * 500000, note.instrument, note.pitch, note.velocity, - MaxVolume * ((totalCount - i) / totalCount))) + result.append( + ( + note.startTime + i * 500, + note.instrument, + note.pitch, + note.velocity, + MaxVolume * ((totalCount - i) / totalCount), + ) + ) return result @@ -838,8 +906,12 @@ class midiConvert: if note_channels.index(track) == 0: CheckFirstChannel = True + SpecialBits = False + elif note_channels.index(track) == 9: + SpecialBits = True else: CheckFirstChannel = False + SpecialBits = False nowTrack = [] @@ -849,11 +921,12 @@ class midiConvert: # 应该是计算的时候出了点小问题 # 我们应该用一个MC帧作为时间单位而不是半秒 - soundID, _X = self.__Inst2soundIDwithX(everynote[1]) + if SpecialBits: + soundID, _X = self.__bitInst2IDwithX(InstID) + else: + soundID, _X = self.__Inst2soundIDwithX(InstID) - score_now = round( - everynote[0] / speed / 50000 - ) + score_now = round(everynote[0] / speed / 50000) maxScore = max(maxScore, score_now) @@ -872,11 +945,11 @@ class midiConvert: return [tracks, cmdAmount, maxScore] def _toCmdList_withDelay_m1( - self, - volume: float = 1.0, - speed: float = 1.0, - player: str = "@a", - isMixedWithPrograssBar=False, + self, + volume: float = 1.0, + speed: float = 1.0, + player: str = "@a", + isMixedWithPrograssBar=False, ) -> list: """ 使用Dislink Sforza的转换思路,将midi转换为我的世界命令列表,并输出每个音符之后的延迟 @@ -948,7 +1021,7 @@ class midiConvert: """ def __replace( - s: str, tobeReplaced: str, replaceWith: str, times: int, other: str + s: str, tobeReplaced: str, replaceWith: str, times: int, other: str ): if times == 0: return s.replace(tobeReplaced, other) @@ -1049,13 +1122,13 @@ class midiConvert: return math.ceil(math.sqrt(math.ceil(total / maxHeight))) def tomcpack( - self, - method: int = 1, - isAutoReset: bool = False, - progressbar=None, - scoreboardname: str = "mscplay", - volume: float = 1.0, - speed: float = 1.0, + self, + method: int = 1, + isAutoReset: bool = False, + progressbar=None, + scoreboardname: str = "mscplay", + volume: float = 1.0, + speed: float = 1.0, ) -> bool or tuple: """ 使用method指定的转换算法,将midi转换为我的世界mcpack格式的包 @@ -1083,7 +1156,7 @@ class midiConvert: # 写入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": "' @@ -1100,7 +1173,7 @@ class midiConvert: ) 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"][ @@ -1124,9 +1197,9 @@ class midiConvert: "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)) indexfile.writelines( @@ -1137,12 +1210,12 @@ class midiConvert: + scoreboardname + " 1\n", ( - "scoreboard players reset @a[scores={" - + scoreboardname - + "=" - + str(maxscore + 20) - + "..}]" - + f" {scoreboardname}\n" + "scoreboard players reset @a[scores={" + + scoreboardname + + "=" + + str(maxscore + 20) + + "..}]" + + f" {scoreboardname}\n" ) if isAutoReset else "", @@ -1153,18 +1226,18 @@ class midiConvert: if progressbar: if progressbar: 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)) ) 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( @@ -1185,15 +1258,15 @@ class midiConvert: return (True, f"转换完成,总长度{maxlen}") def toBDXfile( - self, - method: int = 1, - author: str = "Eilles", - progressbar=False, - maxheight: int = 64, - scoreboardname: str = "mscplay", - volume: float = 1.0, - speed: float = 1.0, - isAutoReset: bool = False, + self, + method: int = 1, + author: str = "Eilles", + progressbar=False, + maxheight: int = 64, + scoreboardname: str = "mscplay", + volume: float = 1.0, + speed: float = 1.0, + isAutoReset: bool = False, ): """ 使用method指定的转换算法,将midi转换为BDX结构文件 @@ -1207,23 +1280,26 @@ class midiConvert: :param isAutoReset: 是否自动重置计分板 :return 成功与否,成功返回(True,未经过压缩的源,结构占用大小),失败返回(False,str失败原因) """ - try: - cmdlist, totalcount, maxScore = self.methods[method - 1]( - scoreboardname, volume, speed - ) - except: - return (False, f"无法找到算法ID{method}对应的转换算法") + # try: + cmdlist, totalcount, maxScore = self.methods[method - 1]( + scoreboardname, volume, speed + ) + # except Exception as E: + # return (False, f"无法找到算法ID{method}对应的转换算法: {E}") if not os.path.exists(self.outputPath): os.makedirs(self.outputPath) - with open(os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), "w+") as f: + with open( + os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), + "w+", + ) as f: f.write("BD@") _bytes = ( - b"BDX\x00" - + author.encode("utf-8") - + b" & Musicreater\x00\x01command_block\x00" + b"BDX\x00" + + author.encode("utf-8") + + b" & Musicreater\x00\x01command_block\x00" ) key = { @@ -1252,12 +1328,12 @@ class midiConvert: if isAutoReset: commands += ( - "scoreboard players reset @a[scores={" - + scoreboardname - + "=" - + str(maxScore + 20) - + "}] " - + scoreboardname + "scoreboard players reset @a[scores={" + + scoreboardname + + "=" + + str(maxScore + 20) + + "}] " + + scoreboardname ) # 此处是对于仅有 True 的参数和自定义参数的判断 @@ -1274,13 +1350,13 @@ class midiConvert: cmd, (1 if yforward else 0) if ( - ((nowy != 0) and (not yforward)) - or ((yforward) and (nowy != maxheight)) + ((nowy != 0) and (not yforward)) + or ((yforward) and (nowy != maxheight)) ) else (3 if zforward else 2) if ( - ((nowz != 0) and (not zforward)) - or ((zforward) and (nowz != _sideLength)) + ((nowz != 0) and (not zforward)) + or ((zforward) and (nowz != _sideLength)) ) else 5, impluse=2, @@ -1302,7 +1378,7 @@ class midiConvert: nowz += 1 if zforward else -1 if ((nowz > _sideLength) and (zforward)) or ( - (nowz < 0) and (not zforward) + (nowz < 0) and (not zforward) ): nowz -= 1 if zforward else -1 zforward = not zforward @@ -1316,20 +1392,23 @@ class midiConvert: _bytes += key[y][int(yforward)] - with open(os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), "ab+") as f: + with open( + os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), + "ab+", + ) as f: f.write(brotli.compress(_bytes + b"XE")) - return (True, _bytes, (nowx, maxheight, _sideLength)) + return (True, totalcount, maxScore, _bytes, (nowx, maxheight, _sideLength)) def toBDXfile_withDelay( - self, - method: int = 1, - author: str = "Eilles", - progressbar=False, - maxheight: int = 64, - volume: float = 1.0, - speed: float = 1.0, - player: str = "@a", + self, + method: int = 1, + author: str = "Eilles", + progressbar=False, + maxheight: int = 64, + volume: float = 1.0, + speed: float = 1.0, + player: str = "@a", ): """ 使用method指定的转换算法,将midi转换为BDX结构文件 @@ -1353,13 +1432,16 @@ class midiConvert: if not os.path.exists(self.outputPath): os.makedirs(self.outputPath) - with open(os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), "w+") as f: + with open( + os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), + "w+", + ) as f: f.write("BD@") _bytes = ( - b"BDX\x00" - + author.encode("utf-8") - + b" & Musicreater\x00\x01command_block\x00" + b"BDX\x00" + + author.encode("utf-8") + + b" & Musicreater\x00\x01command_block\x00" ) key = { @@ -1386,13 +1468,13 @@ class midiConvert: cmd, (1 if yforward else 0) if ( - ((nowy != 0) and (not yforward)) - or ((yforward) and (nowy != maxheight)) + ((nowy != 0) and (not yforward)) + or ((yforward) and (nowy != maxheight)) ) else (3 if zforward else 2) if ( - ((nowz != 0) and (not zforward)) - or ((zforward) and (nowz != _sideLength)) + ((nowz != 0) and (not zforward)) + or ((zforward) and (nowz != _sideLength)) ) else 5, impluse=2, @@ -1414,7 +1496,7 @@ class midiConvert: nowz += 1 if zforward else -1 if ((nowz > _sideLength) and (zforward)) or ( - (nowz < 0) and (not zforward) + (nowz < 0) and (not zforward) ): nowz -= 1 if zforward else -1 zforward = not zforward @@ -1428,11 +1510,15 @@ class midiConvert: _bytes += key[y][int(yforward)] - with open(os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), "ab+") as f: + with open( + os.path.abspath(os.path.join(self.outputPath, f"{self.midFileName}.bdx")), + "ab+", + ) as f: f.write(brotli.compress(_bytes + b"XE")) return (True, _bytes, (nowx, maxheight, _sideLength)) + # def isProgressBar(pgbarLike:str): # '''判断所输入数据是否为进度条式样数据 # 注意,使用本函数时不得直接放在 if 后,正确用法如下: diff --git a/msctPkgver/secrets.7z b/msctPkgver/secrets.7z new file mode 100644 index 0000000..690b780 Binary files /dev/null and b/msctPkgver/secrets.7z differ