史诗级更新!支持导出mcstructure库,更改部分API和文档,修改了部分代码格式,新增红乐测试

This commit is contained in:
EillesWan 2023-04-29 17:00:32 +08:00
parent b758a2f967
commit 4874ace92d
13 changed files with 905 additions and 357 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@
*.mcpack *.mcpack
*.bdx *.bdx
*.json *.json
*.mcstructure
# Byte-compiled / optimized # Byte-compiled / optimized
__pycache__/ __pycache__/

View File

@ -19,8 +19,6 @@ Terms & Conditions: ../License.md
from .main import * from .main import *
__version__ = "0.4.0" __version__ = "0.5.0"
__all__ = [] __all__ = []
__author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray")) __author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray"), ("鸣凤鸽子", "MingFengPigeon"))

View File

@ -25,6 +25,7 @@ class MSCTBaseException(Exception):
"""音·创库版本的所有错误均继承于此""" """音·创库版本的所有错误均继承于此"""
def __init__(self, *args): def __init__(self, *args):
"""音·创库版本的所有错误均继承于此"""
super().__init__(*args) super().__init__(*args)
def miao( def miao(
@ -35,39 +36,67 @@ class MSCTBaseException(Exception):
def crash_it(self): def crash_it(self):
raise self raise self
class CrossNoteError(MSCTBaseException):
"""同通道下同音符交叉出现所产生的错误"""
pass
class NotDefineTempoError(MSCTBaseException): class MidiFormatException(MSCTBaseException):
"""没有Tempo设定导致时间无法计算的错误""" """音·创库版本的所有MIDI格式错误均继承于此"""
pass def __init__(self, *args):
"""音·创库版本的所有MIDI格式错误均继承于此"""
super().__init__("MIDI格式错误", *args)
class MidiDestroyedError(MSCTBaseException): class MidiDestroyedError(MSCTBaseException):
"""Midi文件损坏""" """Midi文件损坏"""
pass def __init__(self, *args):
"""Midi文件损坏"""
super().__init__("MIDI文件损坏无法读取MIDI文件", *args)
class ChannelOverFlowError(MSCTBaseException): class CommandFormatError(RuntimeError):
"""一个midi中含有过多的通道数量应≤16""" """指令格式与目标格式不匹配而引起的错误"""
pass def __init__(self, *args):
"""指令格式与目标格式不匹配而引起的错误"""
super().__init__("指令格式不匹配", *args)
class NotDefineProgramError(MSCTBaseException): class CrossNoteError(MidiFormatException):
"""同通道下同音符交叉出现所产生的错误"""
def __init__(self, *args):
"""同通道下同音符交叉出现所产生的错误"""
super().__init__("同通道下同音符交叉", *args)
class NotDefineTempoError(MidiFormatException):
"""没有Tempo设定导致时间无法计算的错误"""
def __init__(self, *args):
"""没有Tempo设定导致时间无法计算的错误"""
super().__init__("在曲目开始时没有声明Tempo未指定拍长", *args)
class ChannelOverFlowError(MidiFormatException):
"""一个midi中含有过多的通道"""
def __init__(self, max_channel = 16, *args):
"""一个midi中含有过多的通道"""
super().__init__("含有过多的通道(数量应≤{}".format(max_channel), *args)
class NotDefineProgramError(MidiFormatException):
"""没有Program设定导致没有乐器可以选择的错误""" """没有Program设定导致没有乐器可以选择的错误"""
pass def __init__(self, *args):
"""没有Program设定导致没有乐器可以选择的错误"""
super().__init__("未指定演奏乐器", *args)
class ZeroSpeedError(MSCTBaseException): class ZeroSpeedError(MidiFormatException):
"""以0作为播放速度的错误""" """以0作为播放速度的错误"""
pass def __init__(self, *args):
"""以0作为播放速度的错误"""
super().__init__("播放速度为0", *args)

View File

@ -176,4 +176,25 @@ percussion_instrument_list = {
77: ("note.xylophone", 4), 77: ("note.xylophone", 4),
78: ("note.xylophone", 4), 78: ("note.xylophone", 4),
79: ("note.bell", 4), 79: ("note.bell", 4),
80: ("note.bell", 4), } 80: ("note.bell", 4),
}
instrument_to_blocks_list = {
"note.bass": ("planks",),
"note.snare": ("sand",),
"note.hat": ("glass",),
"note.bd": ("stone",),
"note.bell": ("gold_block",),
"note.flute": ("clay",),
"note.chime": ("packed_ice",),
"note.guitar": ("wool",),
"note.xylobone": ("bone_block",),
"note.iron_xylophone": ("iron_block",),
"note.cow_bell": ("soul_sand",),
"note.didgeridoo": ("pumpkin",),
"note.bit": ("emerald_block",),
"note.banjo": ("hay_block",),
"note.pling": ("glowstone",),
"note.bassattack": ("command_block",), # 无法找到此音效
"note.harp": ("glass",),
}

View File

@ -1,35 +1,38 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
功能测试 若非已知 请勿更改
此文件仅供功能测试并非实际调用的文件
请注意此处的文件均为测试使用
不要更改 不要更改 不要更改
请注意这里的一切均需要其原作者更改
这里用于放置一些新奇的点子
用于测试
不要更改 不要更改 不要更改
"""
# 音·创 开发交流群 861684859 # 音·创 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon") # 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon")
# 若需使用或借鉴 请依照 Apache 2.0 许可证进行许可 # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
""" """
· 库版 (Musicreater Package Version) · (Musicreater)
是一款免费开源的针对我的世界基岩版的midi音乐转换库 是一款免费开源的针对我的世界的midi音乐转换库
注意除了此源文件以外任何属于此仓库以及此项目的文件均依照Apache许可证进行许可 Musicreater (·)
Musicreater pkgver (Package Version · 库版) A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
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 版权所有 © 2023 · 开发者
Copyright © 2023 all the developers of Musicreater
Licensed under the Apache License, Version 2.0 (the 'License'); 开源相关声明请见 ../License.md
you may not use this file except in compliance with the License. Terms & Conditions: ../License.md
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.
""" """
def _toCmdList_m1( def _toCmdList_m1(
self, self,
scoreboardname: str = "mscplay", scoreboardname: str = "mscplay",
@ -91,10 +94,6 @@ def _toCmdList_m1(
# ============================ # ============================
@ -102,10 +101,6 @@ def _toCmdList_m1(
import mido import mido
class NoteMessage: class NoteMessage:
def __init__(self, channel, pitch, velocity, startT, lastT, midi, now_bpm, change_bpm=None): def __init__(self, channel, pitch, velocity, startT, lastT, midi, now_bpm, change_bpm=None):
self.channel = channel self.channel = channel
@ -213,5 +208,98 @@ if __name__ == '__main__':
# ============================
from typing import Union
from .utils import x,y,z,bottem_side_length_of_smallest_square_bottom_box,form_note_block_in_NBT_struct,form_repeater_in_NBT_struct
# 不要用 没写完
def delay_to_note_blocks(
baseblock: str = "stone",
position_forward: Union(x, y, z) = z,
max_height: int = 64,
):
"""传入音符,生成以音符盒存储的红石音乐
:param:
baseblock: 中继器的下垫方块
position_forward: 结构延长方向
:return 是否生成成功
"""
from TrimMCStruct import Structure, Block
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
len(commands), max_height
)
struct = Structure(
(_sideLength, max_height, _sideLength), # 声明结构大小
)
log = print
startpos = [0,0,0]
# 1拍 x 2.5 rt
def placeNoteBlock():
for i in notes:
error = True
try:
struct.set_block(
[startpos[0], startpos[1] + 1, startpos[2]],
form_note_block_in_NBT_struct(height2note[i[0]], instrument),
)
struct.set_block(startpos, Block("universal_minecraft", instuments[i[0]][1]),)
error = False
except ValueError:
log("无法放置音符:" + str(i) + "" + str(startpos))
struct.set_block(Block("universal_minecraft", baseblock), startpos)
struct.set_block(
Block("universal_minecraft", baseblock),
[startpos[0], startpos[1] + 1, startpos[2]],
)
finally:
if error is True:
log("无法放置音符:" + str(i) + "" + str(startpos))
struct.set_block(Block("universal_minecraft", baseblock), startpos)
struct.set_block(
Block("universal_minecraft", baseblock),
[startpos[0], startpos[1] + 1, startpos[2]],
)
delay = int(i[1] * speed + 0.5)
if delay <= 4:
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(delay, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
else:
for j in range(int(delay / 4)):
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(4, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
if delay % 4 != 0:
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(delay % 4, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
startpos[0] += posadder[0]
startpos[1] += posadder[1]
startpos[2] += posadder[2]
# e = True
try:
placeNoteBlock()
# e = False
except: # ValueError
log("无法放置方块了,可能是因为区块未加载叭")

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
import math import math
import os import os
from typing import Union
from TrimMCStruct import Structure, Block, TAG_Long, TAG_Byte
key = { bdx_key = {
"x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"], "x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"],
"y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"], "y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"],
"z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"], "z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"],
@ -18,7 +20,7 @@ def bdx_move(axis: str, value: int):
if value == 0: if value == 0:
return b"" return b""
if abs(value) == 1: if abs(value) == 1:
return key[axis][0 if value == -1 else 1] return bdx_key[axis][0 if value == -1 else 1]
pointer = sum( pointer = sum(
[ [
@ -32,7 +34,9 @@ def bdx_move(axis: str, value: int):
] ]
) )
return key[axis][pointer] + value.to_bytes(2 ** (pointer - 2), "big", signed=True) return bdx_key[axis][pointer] + value.to_bytes(
2 ** (pointer - 2), "big", signed=True
)
def compress_zipfile(sourceDir, outFilename, compression=8, exceptFile=None): def compress_zipfile(sourceDir, outFilename, compression=8, exceptFile=None):
@ -112,8 +116,7 @@ def form_command_block_in_BDX_bytes(
:return:str :return:str
""" """
block = b"\x24" + \ block = b"\x24" + particularValue.to_bytes(2, byteorder="big", signed=False)
particularValue.to_bytes(2, byteorder="big", signed=False)
for i in [ for i in [
impluse.to_bytes(4, byteorder="big", signed=False), impluse.to_bytes(4, byteorder="big", signed=False),
@ -138,7 +141,7 @@ def bottem_side_length_of_smallest_square_bottom_box(total: int, maxHeight: int)
return math.ceil(math.sqrt(math.ceil(total / maxHeight))) return math.ceil(math.sqrt(math.ceil(total / maxHeight)))
def to_BDX_bytes( def commands_to_BDX_bytes(
commands: list, commands: list,
max_height: int = 64, max_height: int = 64,
): ):
@ -178,7 +181,7 @@ def to_BDX_bytes(
else (3 if z_forward else 2) else (3 if z_forward else 2)
if ( if (
((now_z != 0) and (not z_forward)) ((now_z != 0) and (not z_forward))
or (z_forward and (now_z != _sideLength)) or (z_forward and (now_z != _sideLength - 1))
) )
else 5, else 5,
impluse=impluse, impluse=impluse,
@ -204,15 +207,13 @@ def to_BDX_bytes(
): ):
now_z -= 1 if z_forward else -1 now_z -= 1 if z_forward else -1
z_forward = not z_forward z_forward = not z_forward
_bytes += key[x][1] _bytes += bdx_key[x][1]
now_x += 1 now_x += 1
else: else:
_bytes += bdx_key[z][int(z_forward)]
_bytes += key[z][int(z_forward)]
else: else:
_bytes += bdx_key[y][int(y_forward)]
_bytes += key[y][int(y_forward)]
return ( return (
_bytes, _bytes,
@ -225,6 +226,60 @@ def to_BDX_bytes(
) )
def form_note_block_in_NBT_struct(
note: int, coordinate: tuple, instrument: str = "note.harp", powered: bool = False
):
"""生成音符盒方块
:param note: `int`(0~24)
音符的音高
:param coordinate: `tuple[int,int,int]`
此方块所在之相对坐标
:param instrument: `str`
音符盒的乐器
:param powered: `bool`
是否已被激活
:return Block
"""
return Block(
"minecraft",
"noteblock",
{
"instrument": instrument.replace("note.", ""),
"note": note,
"powered": powered,
},
{
"block_entity_data": {
"note": TAG_Byte(note),
"id": "noteblock",
"x": coordinate[0],
"y": coordinate[1],
"z": coordinate[2],
}
},
)
def form_repeater_in_NBT_struct(
delay: int, facing: int
):
"""生成中继器方块
:param powered:
:param locked:
:param facing:
:param delay: 1~4
:return Block()"""
return Block(
"minecraft",
"unpowered_repeater",
{
"repeater_delay": delay,
"direction": facing,
},
)
def form_command_block_in_NBT_struct( def form_command_block_in_NBT_struct(
command: str, command: str,
coordinate: tuple, coordinate: tuple,
@ -281,42 +336,43 @@ def form_command_block_in_NBT_struct(
:return:str :return:str
""" """
from TrimMCStruct import Block, TAG_Long
block = Block( return Block(
"minecraft", "minecraft",
"command_block" if impluse == 0 else ( "command_block"
"repeating_command_block" if impluse == 1 else "chain_command_block"), if impluse == 0
states={"conditional_bit": condition, else ("repeating_command_block" if impluse == 1 else "chain_command_block"),
"facing_direction": particularValue}, states={"conditional_bit": condition, "facing_direction": particularValue},
extra_data={ extra_data={
'Command': command, "block_entity_data": {
'CustomName': customName, "Command": command,
'ExecuteOnFirstTick': executeOnFirstTick, "CustomName": customName,
'LPCommandMode': 0, "ExecuteOnFirstTick": executeOnFirstTick,
'LPCondionalMode': False, "LPCommandMode": 0,
'LPRedstoneMode': False, "LPCondionalMode": False,
'LastExecution': TAG_Long(0), "LPRedstoneMode": False,
'LastOutput': '', "LastExecution": TAG_Long(0),
'LastOutputParams': [], "LastOutput": "",
'SuccessCount': 0, "LastOutputParams": [],
'TickDelay': tickDelay, "SuccessCount": 0,
'TrackOutput': trackOutput, "TickDelay": tickDelay,
'Version': 25, "TrackOutput": trackOutput,
'auto': alwaysRun, "Version": 25,
'conditionMet': False, # 是否已经满足条件 "auto": alwaysRun,
'conditionalMode': condition, "conditionMet": False, # 是否已经满足条件
'id': 'CommandBlock', "conditionalMode": condition,
'isMovable': True, "id": "CommandBlock",
'powered': False, # 是否已激活 "isMovable": True,
'x': coordinate[0], "powered": False, # 是否已激活
'y': coordinate[1], "x": coordinate[0],
'z': coordinate[2], "y": coordinate[1],
} "z": coordinate[2],
}
},
compability_version=17959425,
) )
return block
def commands_to_structure(
def to_structure(
commands: list, commands: list,
max_height: int = 64, max_height: int = 64,
): ):
@ -325,8 +381,6 @@ def to_structure(
:param max_height: 生成结构最大高度 :param max_height: 生成结构最大高度
:return 成功与否成功返回(结构类,结构占用大小)失败返回(False,str失败原因) :return 成功与否成功返回(结构类,结构占用大小)失败返回(False,str失败原因)
""" """
# 导入库
from TrimMCStruct import Structure
_sideLength = bottem_side_length_of_smallest_square_bottom_box( _sideLength = bottem_side_length_of_smallest_square_bottom_box(
len(commands), max_height len(commands), max_height
@ -345,29 +399,33 @@ def to_structure(
for cmd, delay in commands: for cmd, delay in commands:
coordinate = (now_x, now_y, now_z) coordinate = (now_x, now_y, now_z)
struct.set_block(coordinate, struct.set_block(
form_command_block_in_NBT_struct( coordinate,
command=cmd, form_command_block_in_NBT_struct(
coordinate=coordinate, command=cmd,
particularValue=(1 if y_forward else 0) coordinate=coordinate,
if ( particularValue=(1 if y_forward else 0)
((now_y != 0) and (not y_forward)) if (
or (y_forward and (now_y != (max_height - 1))) ((now_y != 0) and (not y_forward))
) or (y_forward and (now_y != (max_height - 1)))
else (3 if z_forward else 2) )
if ( else (
((now_z != 0) and (not z_forward)) (3 if z_forward else 2)
or (z_forward and (now_z != _sideLength)) if (
) ((now_z != 0) and (not z_forward))
else 5, or (z_forward and (now_z != _sideLength - 1))
impluse=2, )
condition=False, else 5
alwaysRun=True, ),
tickDelay=delay, impluse=2,
customName="", condition=False,
executeOnFirstTick=False, alwaysRun=True,
trackOutput=True, tickDelay=delay,
)) customName="",
executeOnFirstTick=False,
trackOutput=True,
),
)
now_y += 1 if y_forward else -1 now_y += 1 if y_forward else -1
@ -387,9 +445,11 @@ def to_structure(
return ( return (
struct, struct,
[ (
now_x + 1, now_x + 1,
max_height if now_x or now_z else now_y, max_height if now_x or now_z else now_y,
_sideLength if now_x else now_z, _sideLength if now_x else now_z,
], ),
(now_x, now_y, now_z),
) )

View File

@ -4,7 +4,7 @@
</h1> </h1>
<p align="center"> <p align="center">
<img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png"> <img width="128" height="128" src="https://gitee.com/TriM-Organization/Musicreater/raw/master/resources/msctIcon.ico">
</img> </img>
</p> </p>

View File

@ -4,7 +4,7 @@
<img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png" > <img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png" >
</p> </p>
<h3 align="center">a free open-source library of converting midi files into *Minecraft* formats.</h3> <h3 align="center">a free open-source library of converting midi files into _Minecraft_ formats.</h3>
<p align="center"> <p align="center">
<img src="https://forthebadge.com/images/badges/built-with-love.svg"> <img src="https://forthebadge.com/images/badges/built-with-love.svg">

View File

@ -15,8 +15,10 @@
```python ```python
import Musicreater # 导入转换库 import Musicreater # 导入转换库
old_execute_format = False # 指定是否使用旧的execute指令语法即1.18及以前的《我的世界:基岩版》语法)
# 首先新建转换对象。 # 首先新建转换对象。
conversion = Musicreater.midiConvert() conversion = Musicreater.midiConvert(enable_old_exe_format = old_execute_format)
# 值得注意的是,一个转换对象可以转换多个文件。 # 值得注意的是,一个转换对象可以转换多个文件。
# 也就是在实例化的时候不进行对文件的绑定。 # 也就是在实例化的时候不进行对文件的绑定。
# 如果有调试需要,可以在实例化时传入参数 debug = True # 如果有调试需要,可以在实例化时传入参数 debug = True
@ -26,10 +28,9 @@ conversion = Musicreater.midiConvert()
# 地址都为字符串类型,不能传入文件流 # 地址都为字符串类型,不能传入文件流
midi_path = "./where/you/place/.midi/files.mid" midi_path = "./where/you/place/.midi/files.mid"
output_folder = "./where/you/want2/convert/into/" output_folder = "./where/you/want2/convert/into/"
old_execute_format = False # 指定是否使用旧的execute指令语法即1.18及以前的《我的世界:基岩版》语法)
# 设定基本转换参数 # 设定基本转换参数
conversion.convert(midi_path,output_folder,old_execute_format) conversion.convert(midi_path,output_folder)
# 进行转换并接受输出,具体的参数均在代码之文档中有相关说明 # 进行转换并接受输出,具体的参数均在代码之文档中有相关说明
method_id = 3 # 指定使用的转换算法 method_id = 3 # 指定使用的转换算法
@ -92,13 +93,13 @@ print(convertion_result)
考虑到进行我的世界游戏开发时为了节约常加载区域很多游戏会将指令区设立为一种层叠式的结构这种结构会限制每一层的指令系统的高度但是虽然长宽也是有限的却仍然比其纵轴延伸得更加自由 考虑到进行我的世界游戏开发时为了节约常加载区域很多游戏会将指令区设立为一种层叠式的结构这种结构会限制每一层的指令系统的高度但是虽然长宽也是有限的却仍然比其纵轴延伸得更加自由
所以结构的生成形状依照给定的高度和内含指令的数量决定$Z$轴延伸长度为指令方块数量对于给定高度之商的向下取整结果的平方根的向下取整用数学公式的方式表达则是 所以结构的生成形状依照给定的高度和内含指令的数量决定 $Z$ 轴延伸长度为指令方块数量对于给定高度之商的向下取整结果的平方根的向下取整用数学公式的方式表达则是
$$MaxZ = \left\lfloor\sqrt{\left\lfloor{\frac{NoC}{MaxH}}\right\rfloor}\right\rfloor$$ $$MaxZ = \left\lfloor\sqrt{\left\lfloor{\frac{NoC}{MaxH}}\right\rfloor}\right\rfloor$$
其中$MaxZ$即生成结构的$Z$轴最大延伸长度$NoC$表示链结构中所含指令方块的个数$MaxH$表示给定的生成结构的最大高度 其中$MaxZ$即生成结构的$Z$轴最大延伸长度$NoC$表示链结构中所含指令方块的个数$MaxH$表示给定的生成结构的最大高度
我们的结构生成器在生成指令链时将首先以相对坐标系$(0, 0, 0)$即相对原点开始自下向上堆叠高度轴$Y$的长当高度轴达到了限制的高度时便将$Z$轴向正方向堆叠`1`个方块并开始自上向下重新堆叠直至高度轴坐标达到相对为`0`若当所生成结构的$Z$轴长达到了其最大延伸长度则此结构生成器将反转$Z$轴的堆叠方向直至$Z$轴坐标相对为`0`如此往复直至指令链堆叠完成 我们的结构生成器在生成指令链时将首先以相对坐标系 $(0, 0, 0)$ 即相对原点开始自下向上堆叠高度轴 $Y$ 的长当高度轴达到了限制的高度时便将 $Z$ 轴向正方向堆叠`1`个方块并开始自上向下重新堆叠直至高度轴坐标达到相对为`0`若当所生成结构的 $Z$ 轴长达到了其最大延伸长度则此结构生成器将反转 $Z$ 轴的堆叠方向直至 $Z$ 轴坐标相对为`0`如此往复直至指令链堆叠完成
## 播放器 ## 播放器
@ -121,9 +122,9 @@ print(convertion_result)
|`ScBd`|指定的计分板名称|| |`ScBd`|指定的计分板名称||
|`x`|音发出时对应的分数值|| |`x`|音发出时对应的分数值||
|`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)| |`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)|
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度$S$表示此参数`Ht`以Vol表示音量百分比则计算公式为$S = \frac{1}{Vol}-1$| |`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ |
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9| |`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数$P$表示此参数$n$表示其在MIDI中的编号$x$表示一定的音域偏移则计算公式为$P = 2^\frac{n-60-x}{12}$| |`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号 $x$ 表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
后四个参数决定了这个音的性质而前两个参数仅仅是为了决定音播放的时间 后四个参数决定了这个音的性质而前两个参数仅仅是为了决定音播放的时间
@ -141,9 +142,9 @@ print(convertion_result)
|--------|-----------|----------| |--------|-----------|----------|
|`Tg`|播放对象|选择器或玩家名| |`Tg`|播放对象|选择器或玩家名|
|`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)| |`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)|
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度$S$表示此参数`Ht`以Vol表示音量百分比则计算公式为$S = \frac{1}{Vol}-1$| |`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ |
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9| |`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数$P$表示此参数$n$表示其在MIDI中的编号$x$表示一定的音域偏移则计算公式为$P = 2^\frac{n-60-x}{12}$| |`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号$x$表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
其中后四个参数决定了这个音的性质 其中后四个参数决定了这个音的性质

View File

@ -20,8 +20,6 @@ import os
import Musicreater import Musicreater
# 获取midi列表 # 获取midi列表
midi_path = input(f"请输入MIDI路径") midi_path = input(f"请输入MIDI路径")
@ -46,9 +44,6 @@ fileFormat = int(input(f"请输入输出格式[BDX(1) 或 MCPACK(0)]").lower(
playerFormat = int(input(f"请选择播放方式[计分板(1) 或 延迟(0)]").lower()) playerFormat = int(input(f"请选择播放方式[计分板(1) 或 延迟(0)]").lower())
# 真假字符串判断 # 真假字符串判断
def bool_str(sth: str) -> bool: def bool_str(sth: str) -> bool:
try: try:
@ -61,6 +56,7 @@ def bool_str(sth: str) -> bool:
else: else:
raise ValueError("布尔字符串啊?") raise ValueError("布尔字符串啊?")
debug = False debug = False
if os.path.exists("./demo_config.json"): if os.path.exists("./demo_config.json"):
@ -75,40 +71,40 @@ else:
# 提示语 检测函数 错误提示语 # 提示语 检测函数 错误提示语
for args in [ for args in [
( (
f'输入音量:', f"输入音量:",
float, float,
), ),
( (
f'输入播放速度:', f"输入播放速度:",
float, float,
), ),
( (
f'是否启用进度条:', f"是否启用进度条:",
bool_str, bool_str,
), ),
( (
f'计分板名称:', f"计分板名称:",
str, str,
) )
if playerFormat == 1 if playerFormat == 1
else ( else (
f'玩家选择器:', f"玩家选择器:",
str, str,
), ),
( (
f'是否自动重置计分板:', f"是否自动重置计分板:",
bool_str, bool_str,
) )
if playerFormat == 1 if playerFormat == 1
else (), else (),
( (
f'作者名称:', f"作者名称:",
str, str,
) )
if fileFormat == 1 if fileFormat == 1
else (), else (),
( (
f'最大结构高度:', f"最大结构高度:",
int, int,
) )
if fileFormat == 1 if fileFormat == 1
@ -117,7 +113,7 @@ else:
if args: if args:
prompts.append(args[1](input(args[0]))) prompts.append(args[1](input(args[0])))
conversion = Musicreater.midiConvert(debug) conversion = Musicreater.midiConvert(debug=debug)
print(f"正在处理 {midi_path} ") print(f"正在处理 {midi_path} ")

View File

@ -1,6 +1,8 @@
from Musicreater import midiConvert from Musicreater import midiConvert
conversion = midiConvert() conversion = midiConvert(enable_old_exe_format=False)
conversion.convert(input("midi path:"),input("out path:")) conversion.convert(input("midi路径:"), input("输出路径:"))
conversion.to_mcstructure_file_with_delay(3,)
conversion.to_mcstructure_file_with_delay(
3,
)

View File

@ -1,3 +1,3 @@
Brotli>=1.0.9 Brotli>=1.0.9
mido>=1.2.10 mido>=1.2.10
TrimMCStruct>=0.0.5.5 TrimMCStruct>=0.0.5.6