格式化

This commit is contained in:
bgArray 2022-04-12 14:15:33 +08:00
parent 8f6cc04780
commit 4788d8949b
4 changed files with 72 additions and 59 deletions

View File

@ -1,13 +1,15 @@
#-*- coding:utf-8 -*- # -*- coding:utf-8 -*-
'''一个简单的基于音·创的我的世界音频操作工具''' """一个简单的基于音·创的我的世界音频操作工具"""
import main
if main.importDebug():
print("Debug finished correctly")
else:
print("Debug finished with errors")
__version__ = '0.0.1' __version__ = '0.0.1'
__all__ = [] __all__ = []
__author__ = (('金羿','Eilles Wan'),('诸葛亮与八卦阵','bgArray'),('鸣凤鸽子','MingFengPigeon')) __author__ = (('金羿', 'Eilles Wan'), ('诸葛亮与八卦阵', 'bgArray'), ('鸣凤鸽子', 'MingFengPigeon'))
""" """
Copyright © 2022 Team-Ryoun Copyright © 2022 Team-Ryoun
@ -27,5 +29,3 @@ __author__ = (('金羿','Eilles Wan'),('诸葛亮与八卦阵','bgArray'),('鸣
print('此工具由凌天之云创新团队开发,版权归本团队参与开发的人员共同所有。') print('此工具由凌天之云创新团队开发,版权归本团队参与开发的人员共同所有。')
print('This tool is developed by Team-Ryoun, copyright belongs to the team members who developed the tool.') print('This tool is developed by Team-Ryoun, copyright belongs to the team members who developed the tool.')
from main import *

Binary file not shown.

View File

@ -1,9 +1,7 @@
# THIS PROGRAM IS ONLY A TEST EXAMPLE # THIS PROGRAM IS ONLY A TEST EXAMPLE
if __name__ == '__main__':
from main import * from main import *
one = 1
midiConvert(input('请输入midi文件路径'), input('请输入输出路径:')).tomcpack(1,input('请输入计分板名称:'),float(input('请输入音量0-1')),float(input('请输入速度倍率:'))) midiConvert(input('请输入midi文件路径'), input('请输入输出路径:')).tomcpack(one, input('请输入计分板名称:'), float(input('请输入音量0-1')),
float(input('请输入速度倍率:')))

103
main.py
View File

@ -4,12 +4,10 @@ import mido
import os import os
import json import json
import uuid import uuid
import zipfile
import shutil import shutil
import zipfile import zipfile
def makeZip(sourceDir, outFilename, compression=8, exceptFile=None): def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
"""使用compression指定的算法打包目录为zip文件\n """使用compression指定的算法打包目录为zip文件\n
默认算法为DEFLATED(8),可用算法如下\n 默认算法为DEFLATED(8),可用算法如下\n
@ -30,10 +28,9 @@ def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
zipf.close() zipf.close()
class midiConvert: class midiConvert:
def __init__(self, midiFile: str, outputPath: str): def __init__(self, midiFile: str, outputPath: str):
'''简单的midi转换类将midi文件转换为我的世界结构或者包''' """简单的midi转换类将midi文件转换为我的世界结构或者包"""
self.midiFile = midiFile self.midiFile = midiFile
'''midi文件路径''' '''midi文件路径'''
self.midi = mido.MidiFile(self.midiFile) self.midi = mido.MidiFile(self.midiFile)
@ -44,14 +41,16 @@ class midiConvert:
self.midFileName = os.path.splitext(os.path.basename(self.midiFile))[0] self.midFileName = os.path.splitext(os.path.basename(self.midiFile))[0]
'''文件名,不含路径且不含后缀''' '''文件名,不含路径且不含后缀'''
self.staticDebug = True
def __Inst2SoundID(self, instrumentID, default='note.harp'):
"""返回midi的乐器ID对应的我的世界乐器名
def __Inst2SoundID(self,instrumentID, default='note.harp'):
'''返回midi的乐器ID对应的我的世界乐器名
:param instrumentID: midi的乐器ID :param instrumentID: midi的乐器ID
:param default: 如果instrumentID不在范围内返回的默认我的世界乐器名称 :param default: 如果instrumentID不在范围内返回的默认我的世界乐器名称
:return: 我的世界乐器名 str''' :return: 我的世界乐器名 str"""
if self.staticDebug:
pass
if instrumentID == 105: if instrumentID == 105:
return 'note.banjo' return 'note.banjo'
if instrumentID in range(32, 40): if instrumentID in range(32, 40):
@ -84,54 +83,58 @@ class midiConvert:
return 'note.xylophone' return 'note.xylophone'
return default return default
def _toCmdList_m1(self, scoreboardname: str = 'mscplay', volume: float = 1.0, speed: float = 1.0) -> list:
def _toCmdList_m1(self,scoreboardname : str = 'mscplay',volume:float = 1.0, speed:float = 1.0) -> list: """使用Dislink Sforza的转换算法将midi转换为我的世界命令列表
'''使用Dislink Sforza的转换算法将midi转换为我的世界命令列表
:param scoreboardname: 我的世界的计分板名称 :param scoreboardname: 我的世界的计分板名称
:param volume: 音量注意这里的音量范围为(0,1]如果超出将被处理为正确值其原理为在距离玩家 (1 / volume -1) 的地方播放音频 :param volume: 音量注意这里的音量范围为(0,1]如果超出将被处理为正确值其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度注意这里的速度指的是播放倍率其原理为在播放音频的时候每个音符的播放时间除以 speed :param speed: 速度注意这里的速度指的是播放倍率其原理为在播放音频的时候每个音符的播放时间除以 speed
:return: 我的世界命令列表''' :return: 我的世界命令列表"""
tracks = [] tracks = []
if volume > 1: if volume > 1:
volume = 1 volume = 1
if volume <= 0: if volume <= 0:
volume = 0.001 volume = 0.001
for i, track in enumerate(self.midi.tracks): for i, track in enumerate(self.midi.tracks):
ticks=0 ticks = 0
commands=0 commands = 0
instrumentID=0 instrumentID = 0
singleTrack = [] singleTrack = []
for msg in track: for msg in track:
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': if msg.type == 'program_change':
instrumentID=msg.program instrumentID = msg.program
else: else:
ticks+=msg.time ticks += msg.time
if msg.type == 'note_on' and msg.velocity != 0: if msg.type == 'note_on' and msg.velocity != 0:
singleTrack.append('execute @a[scores={'+scoreboardname+'='+str(round((ticks*tempo)/((self.midi.ticks_per_beat*float(speed))*50000)))+'}'+f'] ~~~ playsound {self.__Inst2SoundID(instrumentID)} @s ~~{1/volume-1}~ {msg.velocity*(0.7 if msg.channel == 0 else 0.9)} {2**((msg.note-66)/12)}') singleTrack.append('execute @a[scores={' + scoreboardname + '=' +
commands+=1 str(round((ticks * tempo)((self.midi.ticks_per_beat * float(speed)) *
50000))) + '}' +
f'] ~~~ playsound {self.__Inst2SoundID(instrumentID)} '
f'@s ~~{1 / volume - 1}~ {msg.velocity * (0.7 if msg.channel == 0 else 0.9)}'
f' {2 ** ((msg.note - 66) / 12)}')
commands += 1
tracks.append(singleTrack) tracks.append(singleTrack)
return tracks return tracks
def tomcpack(self,method:int = 1,scoreboardname : str = 'mscplay',volume:float = 1.0, speed:float = 1.0) -> bool: def tomcpack(self, method: int = 1, scoreboardname: str = 'mscplay', volume: float = 1.0,
'''使用method指定的转换算法将midi转换为我的世界mcpack格式的包 speed: float = 1.0) -> tuple:
"""使用method指定的转换算法将midi转换为我的世界mcpack格式的包
:param method: 转换算法 :param method: 转换算法
:param scoreboardname: 我的世界的计分板名称 :param scoreboardname: 我的世界的计分板名称
:param volume: 音量注意这里的音量范围为(0,1]其原理为在距离玩家 (1 / volume -1) 的地方播放音频 :param volume: 音量注意这里的音量范围为(0,1]其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度注意这里的速度指的是播放倍率其原理为在播放音频的时候每个音符的播放时间除以 speed :param speed: 速度注意这里的速度指的是播放倍率其原理为在播放音频的时候每个音符的播放时间除以 speed
:return 成功与否成功返回(True,True)失败返回(False,str失败原因)''' :return 成功与否成功返回(True,True)失败返回(False,str失败原因)"""
if method == 1: if method == 1:
cmdlist = self._toCmdList_m1(scoreboardname,volume,speed) cmdlist = self._toCmdList_m1(scoreboardname, volume, speed)
else: else:
return (False,f'无法找到算法ID{method}对应的转换算法') return False, f'无法找到算法ID{method}对应的转换算法'
# 当文件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/'):
@ -141,29 +144,41 @@ class midiConvert:
# 写入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(f"{self.outputPath}/temp/manifest.json", "w") as f: with open(f"{self.outputPath}/temp/manifest.json", "w") as f:
f.write("{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + self.midFileName + " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" + self.midFileName + "Pack\",\n \"uuid\": \"" + str(uuid.uuid4()) + "\"\n },\n \"modules\": [\n {\n \"description\": \"" + f"the Player of the Music {self.midFileName}" + "\",\n \"type\": \"data\",\n \"version\": [ 0, 0, 1 ],\n \"uuid\": \"" + str(uuid.uuid4()) + "\"\n }\n ]\n}") f.write(
"{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + self.midFileName +
" Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" + self.midFileName +
"Pack\",\n \"uuid\": \"" + str(
uuid.uuid4()) + "\"\n },\n \"modules\": [\n {\n \"description\": \"" +
f"the Player of the Music {self.midFileName}" + "\",\n \"type\": \"data\",\n "
"\"version\": [ 0, 0, 1 ],\n \"uuid\": "
"\"" + str(
uuid.uuid4()) + "\"\n }\n ]\n}")
else: else:
with open(f'{self.outputPath}/temp/manifest.json', 'r') as manifest: with open(f'{self.outputPath}/temp/manifest.json', 'r') as manifest:
data=json.loads(manifest.read()) data = json.loads(manifest.read())
data['header']['description']=f"the Player of the Music {self.midFileName}" data['header']['description'] = 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').write(json.dumps(data)) open(f'{self.outputPath}/temp/manifest.json', 'w').write(json.dumps(data))
# 将命令列表写入文件 # 将命令列表写入文件
indexfile = open(f'{self.outputPath}/temp/functions/index.mcfunction', 'w', encoding='utf-8') indexfile = open(f'{self.outputPath}/temp/functions/index.mcfunction', 'w', encoding='utf-8')
for track in cmdlist: for track in cmdlist:
indexfile.write('function mscplay/track'+str(cmdlist.index(track)+1)+'\n') indexfile.write('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') as f: with open(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.write('scoreboard players add @a[scores={'+scoreboardname+'=1..}] '+scoreboardname+' 1\n') indexfile.write('scoreboard players add @a[scores={' + scoreboardname + '=1..}] ' + scoreboardname + ' 1\n')
indexfile.close() indexfile.close()
makeZip(f'{self.outputPath}/temp/',self.outputPath+f'/{self.midFileName}.mcpack') makeZip(f'{self.outputPath}/temp/', self.outputPath + f'/{self.midFileName}.mcpack')
shutil.rmtree(f'{self.outputPath}/temp/') shutil.rmtree(f'{self.outputPath}/temp/')
def importDebug():
"""调试用的函数,可以在这里写一些调试代码"""
return None