mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2025-09-03 19:06:23 +00:00
Midi歌词支持,文档格式更新
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,7 @@ RES.txt
|
||||
/Packer/checksum.txt
|
||||
/bgArrayLib
|
||||
/fcwslib
|
||||
test_lyric-mido.py
|
||||
|
||||
# Byte-compiled / optimized
|
||||
__pycache__/
|
||||
|
@ -22,8 +22,8 @@ The Licensor of Musicreater("this project") is Eilles, bgArray.
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
|
||||
__version__ = "2.4.0.1"
|
||||
__vername__ = "全景声支持、音量调节修复"
|
||||
__version__ = "2.4.1"
|
||||
__vername__ = "Midi 歌词支持,文档格式更新"
|
||||
__author__ = (
|
||||
("金羿", "Eilles"),
|
||||
("诸葛亮与八卦阵", "bgArray"),
|
||||
@ -41,13 +41,26 @@ __all__ = [
|
||||
"SingleNoteBox",
|
||||
"ProgressBarStyle",
|
||||
# "TimeStamp", 未来功能
|
||||
# 默认值
|
||||
# 字典键
|
||||
"MIDI_PROGRAM",
|
||||
"MIDI_VOLUME",
|
||||
"MIDI_PAN",
|
||||
# 默认值
|
||||
"MIDI_DEFAULT_PROGRAM_VALUE",
|
||||
"MIDI_DEFAULT_VOLUME_VALUE",
|
||||
"DEFAULT_PROGRESSBAR_STYLE",
|
||||
# Midi 自己的对照表
|
||||
"MIDI_PITCH_NAME_TABLE",
|
||||
"MIDI_PITCHED_NOTE_NAME_GROUP",
|
||||
"MIDI_PITCHED_NOTE_NAME_TABLE",
|
||||
"MIDI_PERCUSSION_NOTE_NAME_TABLE",
|
||||
# Minecraft 自己的对照表
|
||||
"MC_PERCUSSION_INSTRUMENT_LIST",
|
||||
"MC_PITCHED_INSTRUMENT_LIST",
|
||||
"MC_INSTRUMENT_BLOCKS_TABLE",
|
||||
"MC_EILLES_RTJE12_INSTRUMENT_REPLACE_TABLE",
|
||||
"MC_EILLES_RTBETA_INSTRUMENT_REPLACE_TABLE",
|
||||
# Midi 与 游戏 的对照表
|
||||
"MM_INSTRUMENT_RANGE_TABLE",
|
||||
"MM_CLASSIC_PITCHED_INSTRUMENT_TABLE",
|
||||
"MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE",
|
||||
@ -62,10 +75,68 @@ __all__ = [
|
||||
"velocity_2_distance_straight",
|
||||
"panning_2_rotation_linear",
|
||||
"panning_2_rotation_trigonometric",
|
||||
# 工具函数
|
||||
"load_decode_musicsequence_metainfo",
|
||||
"load_decode_msq_flush_release",
|
||||
"load_decode_fsq_flush_release",
|
||||
"guess_deviation",
|
||||
"mctick2timestr",
|
||||
"midi_inst_to_mc_sound",
|
||||
]
|
||||
|
||||
from .main import *
|
||||
from .main import MusicSequence, MidiConvert
|
||||
|
||||
from .subclass import (
|
||||
MineNote,
|
||||
MineCommand,
|
||||
SingleNoteBox,
|
||||
ProgressBarStyle,
|
||||
mctick2timestr,
|
||||
DEFAULT_PROGRESSBAR_STYLE,
|
||||
)
|
||||
|
||||
from .utils import (
|
||||
# 兼容性函数
|
||||
load_decode_musicsequence_metainfo,
|
||||
load_decode_msq_flush_release,
|
||||
load_decode_fsq_flush_release,
|
||||
# 工具函数
|
||||
guess_deviation,
|
||||
midi_inst_to_mc_sound,
|
||||
# 处理用函数
|
||||
velocity_2_distance_natural,
|
||||
velocity_2_distance_straight,
|
||||
panning_2_rotation_linear,
|
||||
panning_2_rotation_trigonometric,
|
||||
)
|
||||
|
||||
from .constants import (
|
||||
# 字典键
|
||||
MIDI_PROGRAM,
|
||||
MIDI_PAN,
|
||||
MIDI_VOLUME,
|
||||
# 默认值
|
||||
MIDI_DEFAULT_PROGRAM_VALUE,
|
||||
MIDI_DEFAULT_VOLUME_VALUE,
|
||||
# MIDI 表
|
||||
MIDI_PITCH_NAME_TABLE,
|
||||
MIDI_PITCHED_NOTE_NAME_GROUP,
|
||||
MIDI_PITCHED_NOTE_NAME_TABLE,
|
||||
MIDI_PERCUSSION_NOTE_NAME_TABLE,
|
||||
# 我的世界 表
|
||||
MC_EILLES_RTBETA_INSTRUMENT_REPLACE_TABLE,
|
||||
MC_EILLES_RTJE12_INSTRUMENT_REPLACE_TABLE,
|
||||
MC_INSTRUMENT_BLOCKS_TABLE,
|
||||
MC_PERCUSSION_INSTRUMENT_LIST,
|
||||
MC_PITCHED_INSTRUMENT_LIST,
|
||||
# MIDI 到 我的世界 表
|
||||
MM_INSTRUMENT_RANGE_TABLE,
|
||||
MM_CLASSIC_PITCHED_INSTRUMENT_TABLE,
|
||||
MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE,
|
||||
MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
|
||||
MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||
MM_DISLINK_PITCHED_INSTRUMENT_TABLE,
|
||||
MM_DISLINK_PERCUSSION_INSTRUMENT_TABLE,
|
||||
MM_NBS_PITCHED_INSTRUMENT_TABLE,
|
||||
MM_NBS_PERCUSSION_INSTRUMENT_TABLE,
|
||||
)
|
||||
|
@ -113,13 +113,20 @@ class NoteOnOffMismatchError(MidiFormatException):
|
||||
"""音符开音和停止不匹配的错误"""
|
||||
super().__init__("音符不匹配", *args)
|
||||
|
||||
class LyricMismatchError(MSCTBaseException):
|
||||
"""歌词匹配解析错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""有可能产生了错误的歌词解析"""
|
||||
super().__init__("歌词解析错误", *args)
|
||||
|
||||
|
||||
class ZeroSpeedError(MSCTBaseException, ZeroDivisionError):
|
||||
"""以0作为播放速度的错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""以0作为播放速度的错误"""
|
||||
super().__init__("播放速度为0", *args)
|
||||
super().__init__("播放速度为零", *args)
|
||||
|
||||
|
||||
class IllegalMinimumVolumeError(MSCTBaseException, ValueError):
|
||||
|
@ -34,6 +34,99 @@ from .types import ChannelType, FittingFunctionType
|
||||
from .utils import *
|
||||
|
||||
|
||||
class FutureMidiConvertLyricSupport(MidiConvert):
|
||||
"""
|
||||
歌词测试支持
|
||||
"""
|
||||
|
||||
def to_command_list_in_delay(
|
||||
self,
|
||||
player_selector: str = "@a",
|
||||
using_lyric: bool = True,
|
||||
) -> Tuple[List[MineCommand], int, int]:
|
||||
"""
|
||||
将midi转换为我的世界命令列表,并输出每个音符之后的延迟
|
||||
|
||||
Parameters
|
||||
----------
|
||||
player_selector: str
|
||||
玩家选择器,默认为`@a`
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple( list[MineCommand指令,...], int音乐时长游戏刻, int最大同时播放的指令数量 )
|
||||
"""
|
||||
|
||||
notes_list: List[MineNote] = sorted(
|
||||
[i for j in self.channels.values() for i in j],
|
||||
key=lambda note: note.start_tick,
|
||||
)
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
self.music_command_list = []
|
||||
multi = max_multi = 0
|
||||
delaytime_previous = 0
|
||||
|
||||
for note in notes_list:
|
||||
if (tickdelay := (note.start_tick - delaytime_previous)) == 0:
|
||||
multi += 1
|
||||
else:
|
||||
max_multi = max(max_multi, multi)
|
||||
multi = 0
|
||||
|
||||
(
|
||||
mc_sound_ID,
|
||||
relative_coordinates,
|
||||
volume_percentage,
|
||||
mc_pitch,
|
||||
) = minenote_to_command_paramaters(
|
||||
note,
|
||||
pitch_deviation=self.music_deviation,
|
||||
)
|
||||
self.music_command_list.append(
|
||||
MineCommand(
|
||||
command=(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ r"playsound {} @s ^{} ^{} ^{} {} {} {}".format(
|
||||
mc_sound_ID,
|
||||
*relative_coordinates,
|
||||
volume_percentage,
|
||||
1.0 if note.percussive else mc_pitch,
|
||||
self.minimum_volume,
|
||||
)
|
||||
),
|
||||
annotation=(
|
||||
"在{}播放噪音{}".format(
|
||||
mctick2timestr(note.start_tick),
|
||||
mc_sound_ID,
|
||||
)
|
||||
if note.percussive
|
||||
else "在{}播放乐音{}".format(
|
||||
mctick2timestr(note.start_tick),
|
||||
"{}:{:.2f}".format(mc_sound_ID, mc_pitch),
|
||||
)
|
||||
),
|
||||
tick_delay=tickdelay,
|
||||
),
|
||||
)
|
||||
if using_lyric and note.extra_info["LYRIC_TEXT"]:
|
||||
self.music_command_list.append(
|
||||
MineCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ 'title @s title " "'
|
||||
)
|
||||
)
|
||||
self.music_command_list.append(
|
||||
MineCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ "title @s subtitle {}".format(note.extra_info["LYRIC_TEXT"])
|
||||
)
|
||||
)
|
||||
delaytime_previous = note.start_tick
|
||||
|
||||
return self.music_command_list, notes_list[-1].start_tick, max_multi + 1
|
||||
|
||||
|
||||
class FutureMidiConvertKamiRES(MidiConvert):
|
||||
"""
|
||||
神羽资源包之测试支持
|
||||
@ -758,10 +851,21 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
_note: MineNote,
|
||||
_apply_time_division: float = 10,
|
||||
) -> List[MineNote]:
|
||||
"""传入音符数据,返回分割后的插值列表
|
||||
:param _note: MineNote 音符
|
||||
:param _apply_time_division: int 间隔帧数
|
||||
:return list[tuple(int开始时间(毫秒), int乐器, int音符, int力度(内置), float音量(播放)),]"""
|
||||
"""
|
||||
传入音符数据,返回分割后的插值列表
|
||||
|
||||
Parameters
|
||||
------------
|
||||
_note: MineNote
|
||||
音符
|
||||
_apply_time_division: int
|
||||
间隔帧数
|
||||
|
||||
Returns
|
||||
---------
|
||||
list[tuple[int, int, int, int, float]]
|
||||
分割后的插值列表,每个元素为 (开始时间(毫秒), 乐器, 音符, 力度(内置), 音量(播放))
|
||||
"""
|
||||
|
||||
if _note.percussive:
|
||||
return [
|
||||
|
@ -130,9 +130,7 @@ class MusicSequence:
|
||||
|
||||
if minimum_volume_of_music > 1 or minimum_volume_of_music <= 0:
|
||||
raise IllegalMinimumVolumeError(
|
||||
"自订的最小音量参数错误:{},应在 (0,1] 范围内。".format(
|
||||
minimum_volume_of_music
|
||||
)
|
||||
"最小音量不得为 {},应在 (0,1] 范围内。".format(minimum_volume_of_music)
|
||||
)
|
||||
# max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
|
||||
|
||||
@ -594,7 +592,7 @@ class MusicSequence:
|
||||
|
||||
else:
|
||||
raise MusicSequenceTypeError(
|
||||
"输入的二进制字节码不是合法的音符序列格式,无法解码,码头前 10 字节为:",
|
||||
"输入的二进制字节码不是正确的音符序列格式,无法解码,码前十字节为:",
|
||||
bytes_buffer_in[:10],
|
||||
)
|
||||
|
||||
@ -851,12 +849,12 @@ class MusicSequence:
|
||||
|
||||
Returns
|
||||
-------
|
||||
以频道作为分割的Midi音符列表字典, 音符总数, 乐器使用统计:
|
||||
Tuple[MineNoteChannelType, int, Dict[str, int]]
|
||||
以通道作为分割的Midi音符列表字典, 音符总数, 乐器使用统计
|
||||
"""
|
||||
|
||||
if speed == 0:
|
||||
raise ZeroSpeedError("播放速度为 0 ,其需要(0,1]范围内的实数。")
|
||||
raise ZeroSpeedError("播放速度不得为零,应为 (0,1] 范围内的实数。")
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
@ -893,8 +891,15 @@ class MusicSequence:
|
||||
],
|
||||
] = empty_midi_channels(default_staff=[])
|
||||
|
||||
lyric_cache: List[Tuple[int, str]] = []
|
||||
|
||||
# 直接使用mido.midifiles.tracks.merge_tracks转为单轨
|
||||
# 采用的时遍历信息思路
|
||||
# 采用的是遍历信息思路
|
||||
|
||||
# 来自 202508 的留言
|
||||
# 该处代码有点问题
|
||||
# merged track 丢失了 track 信息,会导致音符不匹配的问题出现
|
||||
# 应该用遍历 Track 的方式来处理
|
||||
for msg in midi.merged_track:
|
||||
if msg.time != 0:
|
||||
# 微秒
|
||||
@ -904,36 +909,66 @@ class MusicSequence:
|
||||
if msg.type == "set_tempo":
|
||||
tempo = msg.tempo
|
||||
elif msg.type == "program_change":
|
||||
# 检测 乐器变化 之 midi 事件
|
||||
channel_controler[msg.channel][MIDI_PROGRAM] = msg.program
|
||||
|
||||
elif msg.is_cc(7):
|
||||
# Control Change 更改当前通道的 音量 的事件(大幅度)
|
||||
channel_controler[msg.channel][MIDI_VOLUME] = msg.value
|
||||
elif msg.is_cc(10):
|
||||
# Control Change 更改当前通道的 音调偏移 的事件(大幅度)
|
||||
channel_controler[msg.channel][MIDI_PAN] = msg.value
|
||||
|
||||
elif msg.type == "lyrics":
|
||||
# 歌词事件
|
||||
lyric_cache.append((microseconds, msg.text))
|
||||
# print(lyric_cache, flush=True)
|
||||
|
||||
elif msg.type == "note_on" and msg.velocity != 0:
|
||||
# 一个音符开始弹奏
|
||||
|
||||
# 加入音符队列甲(按通道分隔)
|
||||
# (音高,乐器)
|
||||
note_queue_A[msg.channel].append(
|
||||
(msg.note, channel_controler[msg.channel][MIDI_PROGRAM])
|
||||
)
|
||||
# 音符队列乙(按通道分隔)
|
||||
# (力度,微秒)
|
||||
note_queue_B[msg.channel].append((msg.velocity, microseconds))
|
||||
|
||||
elif (msg.type == "note_off") or (
|
||||
msg.type == "note_on" and msg.velocity == 0
|
||||
):
|
||||
# 一个音符结束弹奏
|
||||
|
||||
if (
|
||||
msg.note,
|
||||
channel_controler[msg.channel][MIDI_PROGRAM],
|
||||
) in note_queue_A[msg.channel]:
|
||||
# 在甲队列中发现了同一个 音高和乐器 的音符
|
||||
|
||||
# 获取其音符力度和微秒数
|
||||
_velocity, _ms = note_queue_B[msg.channel][
|
||||
note_queue_A[msg.channel].index(
|
||||
(msg.note, channel_controler[msg.channel][MIDI_PROGRAM])
|
||||
)
|
||||
]
|
||||
|
||||
# 在队列中删除此音符
|
||||
note_queue_A[msg.channel].remove(
|
||||
(msg.note, channel_controler[msg.channel][MIDI_PROGRAM])
|
||||
)
|
||||
note_queue_B[msg.channel].remove((_velocity, _ms))
|
||||
|
||||
_lyric = ""
|
||||
# 找一找歌词吧
|
||||
if lyric_cache:
|
||||
for i in range(len(lyric_cache)):
|
||||
if lyric_cache[i][0] >= _ms:
|
||||
_lyric = lyric_cache.pop(i)[1]
|
||||
break
|
||||
|
||||
# 更新结果信息
|
||||
midi_channels[msg.channel].append(
|
||||
that_note := midi_msgs_to_minenote(
|
||||
inst_=(
|
||||
@ -961,14 +996,19 @@ class MusicSequence:
|
||||
volume_processing_method_=vol_processing_function,
|
||||
panning_processing_method_=pan_processing_function,
|
||||
note_table_replacement=note_rtable_replacement,
|
||||
lyric_line=_lyric,
|
||||
)
|
||||
)
|
||||
|
||||
# 更新统计信息
|
||||
note_count += 1
|
||||
if that_note.sound_name in note_count_per_instrument.keys():
|
||||
note_count_per_instrument[that_note.sound_name] += 1
|
||||
else:
|
||||
note_count_per_instrument[that_note.sound_name] = 1
|
||||
|
||||
else:
|
||||
# 什么?找不到 note on 消息??
|
||||
if ignore_mismatch_error:
|
||||
print(
|
||||
"[WARRING] MIDI格式错误 音符不匹配 {} 无法在上文中找到与之匹配的音符开音消息".format(
|
||||
@ -993,7 +1033,24 @@ class MusicSequence:
|
||||
|
||||
3 音符结束消息
|
||||
("NoteE", 结束的音符ID, 距离演奏开始的毫秒)"""
|
||||
|
||||
del tempo
|
||||
|
||||
if lyric_cache:
|
||||
# 怎么有歌词多啊
|
||||
if ignore_mismatch_error:
|
||||
print(
|
||||
"[WARRING] MIDI 解析错误 歌词对应错误,以下歌词未能填入音符之中,已经填入的仍可能有误 {}".format(
|
||||
lyric_cache
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise LyricMismatchError(
|
||||
"MIDI 解析产生错误",
|
||||
"歌词解析过程中无法对应音符,已填入的音符仍可能有误",
|
||||
lyric_cache,
|
||||
)
|
||||
|
||||
channels = dict(
|
||||
[
|
||||
(channel_no, sorted(channel_notes, key=lambda note: note.start_tick))
|
||||
@ -1126,6 +1183,7 @@ class MidiConvert(MusicSequence):
|
||||
pan_processing_func: FittingFunctionType = panning_2_rotation_linear,
|
||||
music_pitch_deviation: float = 0,
|
||||
note_table_replacement: Dict[str, str] = {},
|
||||
midi_charset: str = "utf-8",
|
||||
):
|
||||
"""
|
||||
直接输入文件地址,将 midi 文件读入
|
||||
@ -1171,6 +1229,7 @@ class MidiConvert(MusicSequence):
|
||||
return cls.from_mido_obj(
|
||||
midi_obj=mido.MidiFile(
|
||||
midi_file_path,
|
||||
charset=midi_charset,
|
||||
clip=True,
|
||||
),
|
||||
midi_name=midi_music_name,
|
||||
|
@ -25,12 +25,28 @@ from typing import List, Literal, Union
|
||||
|
||||
|
||||
def compress_zipfile(sourceDir, outFilename, compression=8, exceptFile=None):
|
||||
"""使用compression指定的算法打包目录为zip文件\n
|
||||
默认算法为DEFLATED(8),可用算法如下:\n
|
||||
STORED = 0\n
|
||||
DEFLATED = 8\n
|
||||
BZIP2 = 12\n
|
||||
LZMA = 14\n
|
||||
"""
|
||||
使用指定的压缩算法将目录打包为zip文件
|
||||
|
||||
Parameters
|
||||
------------
|
||||
sourceDir: str
|
||||
要压缩的源目录路径
|
||||
outFilename: str
|
||||
输出的zip文件路径
|
||||
compression: int, 可选
|
||||
压缩算法,默认为8 (DEFLATED)
|
||||
可用算法:
|
||||
STORED = 0
|
||||
DEFLATED = 8 (默认)
|
||||
BZIP2 = 12
|
||||
LZMA = 14
|
||||
exceptFile: list[str], 可选
|
||||
需要排除在压缩包外的文件名称列表(可选)
|
||||
|
||||
Returns
|
||||
---------
|
||||
None
|
||||
"""
|
||||
|
||||
zipf = zipfile.ZipFile(outFilename, "w", compression)
|
||||
|
@ -60,50 +60,55 @@ def form_command_block_in_BDX_bytes(
|
||||
customName: str = "",
|
||||
executeOnFirstTick: bool = False,
|
||||
trackOutput: bool = True,
|
||||
):
|
||||
) -> bytes:
|
||||
"""
|
||||
使用指定项目返回指定的指令方块放置指令项
|
||||
:param command: `str`
|
||||
使用指定参数生成指定的指令方块放置指令项
|
||||
|
||||
Parameters
|
||||
------------
|
||||
command: str
|
||||
指令
|
||||
:param particularValue:
|
||||
particularValue: int
|
||||
方块特殊值,即朝向
|
||||
:0 下 无条件
|
||||
:1 上 无条件
|
||||
:2 z轴负方向 无条件
|
||||
:3 z轴正方向 无条件
|
||||
:4 x轴负方向 无条件
|
||||
:5 x轴正方向 无条件
|
||||
:6 下 无条件
|
||||
:7 下 无条件
|
||||
|
||||
:8 下 有条件
|
||||
:9 上 有条件
|
||||
:10 z轴负方向 有条件
|
||||
:11 z轴正方向 有条件
|
||||
:12 x轴负方向 有条件
|
||||
:13 x轴正方向 有条件
|
||||
:14 下 有条件
|
||||
:14 下 有条件
|
||||
:0 下 无条件
|
||||
:1 上 无条件
|
||||
:2 z轴负方向 无条件
|
||||
:3 z轴正方向 无条件
|
||||
:4 x轴负方向 无条件
|
||||
:5 x轴正方向 无条件
|
||||
:6 下 无条件
|
||||
:7 下 无条件
|
||||
:8 下 有条件
|
||||
:9 上 有条件
|
||||
:10 z轴负方向 有条件
|
||||
:11 z轴正方向 有条件
|
||||
:12 x轴负方向 有条件
|
||||
:13 x轴正方向 有条件
|
||||
:14 下 有条件
|
||||
:14 下 有条件
|
||||
注意!此处特殊值中的条件会被下面condition参数覆写
|
||||
:param impluse: `int 0|1|2`
|
||||
impluse: int (0|1|2)
|
||||
方块类型
|
||||
0脉冲 1循环 2连锁
|
||||
:param condition: `bool`
|
||||
0脉冲 1循环 2连锁
|
||||
condition: bool
|
||||
是否有条件
|
||||
:param needRedstone: `bool`
|
||||
needRedstone: bool
|
||||
是否需要红石
|
||||
:param tickDelay: `int`
|
||||
tickDelay: int
|
||||
执行延时
|
||||
:param customName: `str`
|
||||
customName: str
|
||||
悬浮字
|
||||
lastOutput: `str`
|
||||
上次输出字符串,注意此处需要留空
|
||||
:param executeOnFirstTick: `bool`
|
||||
首刻执行(循环指令方块是否激活后立即执行,若为False,则从激活时起延迟后第一次执行)
|
||||
:param trackOutput: `bool`
|
||||
是否输出
|
||||
lastOutput: str
|
||||
命令方块的上次输出字符串,注意此处需要留空
|
||||
executeOnFirstTick: bool
|
||||
是否启用首刻执行(循环指令方块是否激活后立即执行,若为False,则从激活时起延迟后第一次执行)
|
||||
trackOutput: bool
|
||||
是否启用命令方块输出
|
||||
|
||||
:return:str
|
||||
Returns
|
||||
---------
|
||||
bytes
|
||||
用以生成 bdx 结构的字节码
|
||||
"""
|
||||
block = b"\x24" + particularValue.to_bytes(2, byteorder="big", signed=False)
|
||||
|
||||
@ -127,9 +132,19 @@ def commands_to_BDX_bytes(
|
||||
max_height: int = 64,
|
||||
):
|
||||
"""
|
||||
:param commands: 指令列表(指令, 延迟)
|
||||
:param max_height: 生成结构最大高度
|
||||
:return 成功与否,成功返回(True,未经过压缩的源,结构占用大小),失败返回(False,str失败原因)
|
||||
指令列表转换为用以生成 bdx 结构的字节码
|
||||
|
||||
Parameters
|
||||
------------
|
||||
commands: list[tuple[str, int]]
|
||||
指令列表,每个元素为 (指令, 延迟)
|
||||
max_height: int
|
||||
生成结构最大高度
|
||||
|
||||
Returns
|
||||
---------
|
||||
tuple[bool, bytes, int] or tuple[bool, str]
|
||||
成功与否,成功返回 (True, 未经过压缩的源, 结构占用大小),失败返回 (False, str失败原因)
|
||||
"""
|
||||
|
||||
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
|
||||
|
@ -19,9 +19,22 @@ Terms & Conditions: License.md in the root directory
|
||||
import math
|
||||
|
||||
|
||||
def bottem_side_length_of_smallest_square_bottom_box(total: int, maxHeight: int):
|
||||
"""给定总方块数量和最大高度,返回所构成的图形外切正方形的边长
|
||||
:param total: 总方块数量
|
||||
:param maxHeight: 最大高度
|
||||
:return: 外切正方形的边长 int"""
|
||||
return math.ceil(math.sqrt(math.ceil(total / maxHeight)))
|
||||
def bottem_side_length_of_smallest_square_bottom_box(
|
||||
_total_block_count: int, _max_height: int
|
||||
):
|
||||
"""
|
||||
给定结构的总方块数量和规定的最大高度,返回该结构应当构成的图形,在底面的外切正方形之边长
|
||||
|
||||
Parameters
|
||||
------------
|
||||
_total_block_count: int
|
||||
总方块数量
|
||||
_max_height: int
|
||||
规定的结构最大高度
|
||||
|
||||
Returns
|
||||
---------
|
||||
int
|
||||
外切正方形的边长
|
||||
"""
|
||||
return math.ceil(math.sqrt(math.ceil(_total_block_count / _max_height)))
|
||||
|
@ -70,17 +70,25 @@ def form_note_block_in_NBT_struct(
|
||||
instrument: str = "note.harp",
|
||||
powered: bool = False,
|
||||
compability_version_number: int = COMPABILITY_VERSION_119,
|
||||
):
|
||||
"""生成音符盒方块
|
||||
:param note: `int`(0~24)
|
||||
) -> Block:
|
||||
"""
|
||||
生成音符盒方块
|
||||
|
||||
Parameters
|
||||
------------
|
||||
note: int (0~24)
|
||||
音符的音高
|
||||
:param coordinate: `tuple[int,int,int]`
|
||||
coordinate: tuple[int, int, int]
|
||||
此方块所在之相对坐标
|
||||
:param instrument: `str`
|
||||
instrument: str
|
||||
音符盒的乐器
|
||||
:param powered: `bool`
|
||||
powered: bool
|
||||
是否已被激活
|
||||
:return Block
|
||||
|
||||
Returns
|
||||
-------
|
||||
Block
|
||||
生成的方块对象
|
||||
"""
|
||||
|
||||
return Block(
|
||||
@ -108,15 +116,26 @@ def form_repeater_in_NBT_struct(
|
||||
delay: int,
|
||||
facing: int,
|
||||
compability_version_number: int = COMPABILITY_VERSION_119,
|
||||
):
|
||||
"""生成中继器方块
|
||||
:param facing: 朝向:
|
||||
) -> Block:
|
||||
"""
|
||||
生成中继器方块
|
||||
|
||||
Parameters
|
||||
----------
|
||||
facing: int (0~3)
|
||||
朝向:
|
||||
Z- 北 0
|
||||
X- 东 1
|
||||
Z+ 南 2
|
||||
X+ 西 3
|
||||
:param delay: 0~3
|
||||
:return Block()"""
|
||||
delay: int (0~3)
|
||||
信号延迟
|
||||
|
||||
Returns
|
||||
-------
|
||||
Block
|
||||
生成的方块对象
|
||||
"""
|
||||
|
||||
return Block(
|
||||
"minecraft",
|
||||
@ -141,50 +160,58 @@ def form_command_block_in_NBT_struct(
|
||||
executeOnFirstTick: bool = False,
|
||||
trackOutput: bool = True,
|
||||
compability_version_number: int = COMPABILITY_VERSION_119,
|
||||
):
|
||||
) -> Block:
|
||||
"""
|
||||
使用指定项目返回指定的指令方块结构
|
||||
:param command: `str`
|
||||
使用指定参数生成指令方块
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
command: str
|
||||
指令
|
||||
:param coordinate: `tuple[int,int,int]`
|
||||
coordinate: tuple[int,int,int]
|
||||
此方块所在之相对坐标
|
||||
:param particularValue:
|
||||
particularValue: int
|
||||
方块特殊值,即朝向
|
||||
:0 下 无条件
|
||||
:1 上 无条件
|
||||
:2 z轴负方向 无条件
|
||||
:3 z轴正方向 无条件
|
||||
:4 x轴负方向 无条件
|
||||
:5 x轴正方向 无条件
|
||||
:6 下 无条件
|
||||
:7 下 无条件
|
||||
|
||||
:8 下 有条件
|
||||
:9 上 有条件
|
||||
:10 z轴负方向 有条件
|
||||
:11 z轴正方向 有条件
|
||||
:12 x轴负方向 有条件
|
||||
:13 x轴正方向 有条件
|
||||
:14 下 有条件
|
||||
:14 下 有条件
|
||||
:0 下 无条件
|
||||
:1 上 无条件
|
||||
:2 z轴负方向 无条件
|
||||
:3 z轴正方向 无条件
|
||||
:4 x轴负方向 无条件
|
||||
:5 x轴正方向 无条件
|
||||
:6 下 无条件
|
||||
:7 下 无条件
|
||||
:8 下 有条件
|
||||
:9 上 有条件
|
||||
:10 z轴负方向 有条件
|
||||
:11 z轴正方向 有条件
|
||||
:12 x轴负方向 有条件
|
||||
:13 x轴正方向 有条件
|
||||
:14 下 有条件
|
||||
:14 下 有条件
|
||||
注意!此处特殊值中的条件会被下面condition参数覆写
|
||||
:param impluse: `int 0|1|2`
|
||||
impluse: int (0|1|2)
|
||||
方块类型
|
||||
0脉冲 1循环 2连锁
|
||||
:param condition: `bool`
|
||||
0脉冲 1循环 2连锁
|
||||
condition: bool
|
||||
是否有条件
|
||||
:param alwaysRun: `bool`
|
||||
alwaysRun: bool
|
||||
是否始终执行
|
||||
:param tickDelay: `int`
|
||||
tickDelay: int
|
||||
执行延时
|
||||
:param customName: `str`
|
||||
customName: str
|
||||
悬浮字
|
||||
:param executeOnFirstTick: `bool`
|
||||
首刻执行(循环指令方块是否激活后立即执行,若为False,则从激活时起延迟后第一次执行)
|
||||
:param trackOutput: `bool`
|
||||
是否输出
|
||||
executeOnFirstTick: bool
|
||||
是否启用首刻执行(循环指令方块是否激活后立即执行,若为False,则从激活时起延迟后第一次执行)
|
||||
trackOutput: bool
|
||||
是否启用命令方块输出
|
||||
compability_version_number: int
|
||||
版本兼容代号
|
||||
|
||||
:return:str
|
||||
Returns
|
||||
-------
|
||||
Block
|
||||
生成的方块对象
|
||||
"""
|
||||
|
||||
return Block(
|
||||
@ -231,9 +258,19 @@ def commands_to_structure(
|
||||
compability_version_: int = COMPABILITY_VERSION_119,
|
||||
):
|
||||
"""
|
||||
:param commands: 指令列表
|
||||
:param max_height: 生成结构最大高度
|
||||
:return 结构类,结构占用大小,终点坐标
|
||||
由指令列表生成(纯指令方块)结构
|
||||
|
||||
Parameters
|
||||
------------
|
||||
commands: list
|
||||
指令列表
|
||||
max_height: int
|
||||
生成结构最大高度
|
||||
|
||||
Returns
|
||||
---------
|
||||
Structure, tuple[int, int, int], tuple[int, int, int]
|
||||
结构类, 结构占用大小, 终点坐标
|
||||
"""
|
||||
|
||||
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
|
||||
@ -321,12 +358,25 @@ def commands_to_redstone_delay_structure(
|
||||
compability_version_: int = COMPABILITY_VERSION_119,
|
||||
) -> Tuple[Structure, Tuple[int, int, int], Tuple[int, int, int]]:
|
||||
"""
|
||||
:param commands: 指令列表
|
||||
:param delay_length: 延时总长
|
||||
:param max_multicmd_length: 最大同时播放的音符数量
|
||||
:param base_block: 生成结构的基底方块
|
||||
:param axis_: 生成结构的延展方向
|
||||
:return 结构类,结构占用大小,终点坐标
|
||||
由指令列表生成由红石中继器延迟的结构
|
||||
|
||||
Parameters
|
||||
------------
|
||||
commands: list
|
||||
指令列表
|
||||
delay_length: int
|
||||
延时总长
|
||||
max_multicmd_length: int
|
||||
最大同时播放的音符数量
|
||||
base_block: Block
|
||||
生成结构的基底方块
|
||||
axis_: str
|
||||
生成结构的延展方向
|
||||
|
||||
Returns
|
||||
---------
|
||||
Structure, tuple[int, int, int], tuple[int, int, int]
|
||||
结构类, 结构占用大小, 终点坐标
|
||||
"""
|
||||
if axis_ in ["z+", "Z+"]:
|
||||
extensioon_direction = z
|
||||
|
@ -70,23 +70,41 @@ class MineNote:
|
||||
azimuth: Optional[Tuple[float, float]] = None,
|
||||
extra_information: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""用于存储单个音符的类
|
||||
"""
|
||||
用于存储单个音符的类
|
||||
|
||||
:param mc_sound_name:`str` 《我的世界》声音ID
|
||||
:param midi_pitch:`int` midi音高
|
||||
:param midi_velocity:`int` midi响度(力度)
|
||||
:param start_time:`int` 开始之时(命令刻)
|
||||
Parameters
|
||||
------------
|
||||
mc_sound_name: str
|
||||
《我的世界》声音ID
|
||||
midi_pitch: int
|
||||
midi音高
|
||||
midi_velocity: int
|
||||
midi响度(力度)
|
||||
start_time: int
|
||||
开始之时(命令刻)
|
||||
注:此处的时间是用从乐曲开始到当前的刻数
|
||||
:param last_time:`int` 音符延续时间(命令刻)
|
||||
:param mass_precision_time:`int` 高精度的开始时间偏移量(1/1250秒)
|
||||
:param is_percussion:`bool` 是否作为打击乐器
|
||||
:param distance: `float` 发声源距离玩家的距离(半径 `r`)
|
||||
last_time: int
|
||||
音符延续时间(命令刻)
|
||||
mass_precision_time: int
|
||||
高精度的开始时间偏移量(1/1250秒)
|
||||
is_percussion: bool
|
||||
是否作为打击乐器
|
||||
distance: float
|
||||
发声源距离玩家的距离(半径 `r`)
|
||||
注:距离越近,音量越高,默认为 0。此参数可以与音量成某种函数关系。
|
||||
:param azimuth:`tuple[float, float]` 声源方位
|
||||
azimuth: tuple[float, float]
|
||||
声源方位
|
||||
注:此参数为tuple,包含两个元素,分别表示:
|
||||
`rV` 发声源在竖直(上下)轴上,从玩家视角正前方开始,向顺时针旋转的角度
|
||||
`rH` 发声源在水平(左右)轴上,从玩家视角正前方开始,向上(到达玩家正上方顶点后变为向下,以此类推的旋转)旋转的角度
|
||||
:param extra_information:`Any` 附加信息"""
|
||||
extra_information: Any
|
||||
附加信息,尽量存储为字典
|
||||
|
||||
Returns
|
||||
---------
|
||||
MineNote 类
|
||||
"""
|
||||
self.sound_name: str = mc_sound_name
|
||||
"""乐器ID"""
|
||||
self.note_pitch: int = 66 if midi_pitch is None else midi_pitch
|
||||
@ -94,9 +112,9 @@ class MineNote:
|
||||
self.velocity: int = midi_velocity
|
||||
"""响度(力度)"""
|
||||
self.start_tick: int = start_time
|
||||
"""开始之时 tick"""
|
||||
"""开始之时 命令刻"""
|
||||
self.duration: int = last_time
|
||||
"""音符持续时间 tick"""
|
||||
"""音符持续时间 命令刻"""
|
||||
self.high_precision_time: int = mass_precision_time
|
||||
"""高精度开始时间偏量 0.4 毫秒"""
|
||||
|
||||
@ -133,17 +151,35 @@ class MineNote:
|
||||
displacement: Optional[Tuple[float, float, float]] = None,
|
||||
extra_information: Optional[Any] = None,
|
||||
):
|
||||
"""用于存储单个音符的类
|
||||
:param mc_sound_name:`str` 《我的世界》声音ID
|
||||
:param midi_pitch:`int` midi音高
|
||||
:param midi_velocity:`int` midi响度(力度)
|
||||
:param start_time:`int` 开始之时(命令刻)
|
||||
"""
|
||||
从传统音像位移格式传参,写入用于存储单个音符的类
|
||||
|
||||
Parameters
|
||||
------------
|
||||
mc_sound_name: str
|
||||
《我的世界》声音ID
|
||||
midi_pitch: int
|
||||
midi音高
|
||||
midi_velocity: int
|
||||
midi响度(力度)
|
||||
start_time: int
|
||||
开始之时(命令刻)
|
||||
注:此处的时间是用从乐曲开始到当前的刻数
|
||||
:param last_time:`int` 音符延续时间(命令刻)
|
||||
:param mass_precision_time:`int` 高精度的开始时间偏移量(1/1250秒)
|
||||
:param is_percussion:`bool` 是否作为打击乐器
|
||||
:param displacement:`tuple[float,float,float]` 声像位移
|
||||
:param extra_information:`Any` 附加信息"""
|
||||
last_time: int
|
||||
音符延续时间(命令刻)
|
||||
mass_precision_time: int
|
||||
高精度的开始时间偏移量(1/1250秒)
|
||||
is_percussion: bool
|
||||
是否作为打击乐器
|
||||
displacement: tuple[float, float, float]
|
||||
声像位移
|
||||
extra_information: Any
|
||||
附加信息,尽量为字典。
|
||||
|
||||
Returns
|
||||
---------
|
||||
MineNote 类
|
||||
"""
|
||||
|
||||
if displacement is None:
|
||||
displacement = (0, 0, 0)
|
||||
@ -246,10 +282,17 @@ class MineNote:
|
||||
"""
|
||||
将数据打包为字节码
|
||||
|
||||
:param is_displacement_included:`bool` 是否包含声像偏移数据,默认为**是**
|
||||
:param is_high_time_precision:`bool` 是否启用高精度,默认为**是**
|
||||
Parameters
|
||||
------------
|
||||
is_displacement_included: bool
|
||||
是否包含声像偏移数据,默认为**是**
|
||||
is_high_time_precision: bool
|
||||
是否启用高精度,默认为**是**
|
||||
|
||||
:return bytes 打包好的字节码
|
||||
Returns
|
||||
---------
|
||||
bytes
|
||||
打包好的字节码
|
||||
"""
|
||||
|
||||
# MineNote 的字节码共有三个顺次版本分别如下
|
||||
@ -545,12 +588,26 @@ class SingleNoteBox:
|
||||
percussion: Optional[bool] = None,
|
||||
annotation: str = "",
|
||||
):
|
||||
"""用于存储单个音符盒的类
|
||||
:param instrument_block_ 音符盒演奏所使用的乐器方块
|
||||
:param note_value_ 音符盒的演奏音高
|
||||
:param percussion 此音符盒乐器是否作为打击乐处理
|
||||
"""
|
||||
用于存储单个音符盒的类
|
||||
|
||||
Parameters
|
||||
------------
|
||||
instrument_block_: str
|
||||
音符盒演奏所使用的乐器方块
|
||||
note_value_: int
|
||||
音符盒的演奏音高
|
||||
percussion: bool
|
||||
此音符盒乐器是否作为打击乐处理
|
||||
注:若为空,则自动识别是否为打击乐器
|
||||
:param annotation 音符注释"""
|
||||
annotation: Any
|
||||
音符注释
|
||||
|
||||
Returns
|
||||
---------
|
||||
SingleNoteBox 类
|
||||
"""
|
||||
|
||||
self.instrument_block = instrument_block_
|
||||
"""乐器方块"""
|
||||
self.note_value = note_value_
|
||||
@ -634,7 +691,8 @@ class ProgressBarStyle:
|
||||
to_play_s: Optional[str] = None,
|
||||
played_s: Optional[str] = None,
|
||||
):
|
||||
"""用于存储进度条样式的类
|
||||
"""
|
||||
用于存储进度条样式的类
|
||||
|
||||
| 标识符 | 指定的可变量 |
|
||||
|---------|----------------|
|
||||
@ -646,9 +704,18 @@ class ProgressBarStyle:
|
||||
| `%%%` | 当前进度比率 |
|
||||
| `_` | 用以表示进度条占位|
|
||||
|
||||
:param base_s 基础样式,用以定义进度条整体
|
||||
:param to_play_s 进度条样式:尚未播放的样子
|
||||
:param played_s 已经播放的样子
|
||||
Parameters
|
||||
------------
|
||||
base_s: str
|
||||
基础样式,用以定义进度条整体
|
||||
to_play_s: str
|
||||
进度条样式:尚未播放的样子
|
||||
played_s: str
|
||||
已经播放的样子
|
||||
|
||||
Returns
|
||||
---------
|
||||
ProgressBarStyle 类
|
||||
"""
|
||||
|
||||
self.base_style = (
|
||||
@ -709,9 +776,19 @@ class ProgressBarStyle:
|
||||
"""
|
||||
直接依照此格式输出一个进度条
|
||||
|
||||
:param played_delays: int 当前播放进度积分值
|
||||
:param total_delays: int 乐器总延迟数(积分数)
|
||||
:param music_name: str 曲名
|
||||
Parameters
|
||||
------------
|
||||
played_delays: int
|
||||
当前播放进度积分值
|
||||
total_delays: int
|
||||
乐器总延迟数(计分板值)
|
||||
music_name: str
|
||||
曲名
|
||||
|
||||
Returns
|
||||
---------
|
||||
str
|
||||
进度条字符串
|
||||
"""
|
||||
|
||||
return (
|
||||
|
@ -136,7 +136,7 @@ def velocity_2_distance_natural(
|
||||
Parameters
|
||||
----------
|
||||
vol: int
|
||||
midi音符力度值
|
||||
midi 音符力度值
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -162,7 +162,7 @@ def velocity_2_distance_straight(vol: float) -> float:
|
||||
Parameters
|
||||
----------
|
||||
vol: int
|
||||
midi音符力度值
|
||||
midi 音符力度值
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -179,7 +179,7 @@ def panning_2_rotation_linear(pan_: float) -> float:
|
||||
----------
|
||||
pan_: int
|
||||
Midi 左右平衡偏移值
|
||||
注:此参数为int,范围从0到127,当为 64 时,声源居中
|
||||
注:此参数为int,范围从 0 到 127,当为 64 时,声源居中
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -197,7 +197,7 @@ def panning_2_rotation_trigonometric(pan_: float) -> float:
|
||||
----------
|
||||
pan_: int
|
||||
Midi 左右平衡偏移值
|
||||
注:此参数为int,范围从0到127,当为 64 时,声源居中
|
||||
注:此参数为int,范围从 0 到 127,当为 64 时,声源居中
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -222,11 +222,19 @@ def minenote_to_command_paramaters(
|
||||
Union[float, Literal[None]],
|
||||
]:
|
||||
"""
|
||||
将MineNote对象转为《我的世界》音符播放所需之参数
|
||||
:param note_:MineNote 音符对象
|
||||
:param deviation:float 音调偏移量
|
||||
将 MineNote 对象转为《我的世界》音符播放所需之参数
|
||||
|
||||
:return str[我的世界音符ID], Tuple[float,float,float]播放视角坐标, float[指令音量参数], float[指令音调参数]
|
||||
Parameters
|
||||
------------
|
||||
note_: MineNote
|
||||
音符对象
|
||||
deviation: float
|
||||
音调偏移量
|
||||
|
||||
Returns
|
||||
---------
|
||||
str, tuple[float, float, float], float, float
|
||||
我的世界音符ID, 播放视角坐标, 指令音量参数, 指令音调参数
|
||||
"""
|
||||
|
||||
return (
|
||||
@ -252,7 +260,6 @@ def minenote_to_command_paramaters(
|
||||
)
|
||||
|
||||
|
||||
|
||||
def midi_msgs_to_minenote(
|
||||
inst_: int, # 乐器编号
|
||||
note_: int,
|
||||
@ -267,24 +274,46 @@ def midi_msgs_to_minenote(
|
||||
volume_processing_method_: FittingFunctionType,
|
||||
panning_processing_method_: FittingFunctionType,
|
||||
note_table_replacement: Dict[str, str] = {},
|
||||
lyric_line: str = "",
|
||||
) -> MineNote:
|
||||
"""
|
||||
将Midi信息转为我的世界音符对象
|
||||
:param inst_: int 乐器编号
|
||||
:param note_: int 音高编号(音符编号)
|
||||
:param percussive_: bool 是否作为打击乐器启用
|
||||
:param volume_: int 音量
|
||||
:param velocity_: int 力度
|
||||
:param panning_: int 声相偏移
|
||||
:param start_time_: int 音符起始时间(微秒)
|
||||
:param duration_: int 音符持续时间(微秒)
|
||||
:param play_speed: float 曲目播放速度
|
||||
:param midi_reference_table: Dict[int, str] 转换对照表
|
||||
:param volume_processing_method_: Callable[[float], float] 音量处理函数
|
||||
:param panning_processing_method_: Callable[[float], float] 立体声相偏移处理函数
|
||||
:param note_table_replacement: Dict[str, str] 音符替换表,定义 Minecraft 音符字串的替换
|
||||
|
||||
:return MineNote我的世界音符对象
|
||||
Parameters
|
||||
------------
|
||||
inst_: int
|
||||
乐器编号
|
||||
note_: int
|
||||
音高编号(音符编号)
|
||||
percussive_: bool
|
||||
是否作为打击乐器启用
|
||||
volume_: int
|
||||
音量
|
||||
velocity_: int
|
||||
力度
|
||||
panning_: int
|
||||
声相偏移
|
||||
start_time_: int
|
||||
音符起始时间(微秒)
|
||||
duration_: int
|
||||
音符持续时间(微秒)
|
||||
play_speed: float
|
||||
曲目播放速度
|
||||
midi_reference_table: Dict[int, str]
|
||||
转换对照表
|
||||
volume_processing_method_: Callable[[float], float]
|
||||
音量处理函数
|
||||
panning_processing_method_: Callable[[float], float]
|
||||
立体声相偏移处理函数
|
||||
note_table_replacement: Dict[str, str]
|
||||
音符替换表,定义 Minecraft 音符字串的替换
|
||||
lyric_line: str
|
||||
该音符的歌词
|
||||
|
||||
Returns
|
||||
---------
|
||||
MineNote
|
||||
我的世界音符对象
|
||||
"""
|
||||
mc_sound_ID = midi_inst_to_mc_sound(
|
||||
inst_,
|
||||
@ -302,6 +331,11 @@ def midi_msgs_to_minenote(
|
||||
is_percussion=percussive_,
|
||||
distance=volume_processing_method_(volume_),
|
||||
azimuth=(panning_processing_method_(panning_), 0),
|
||||
extra_information={
|
||||
"LYRIC_TEXT": lyric_line,
|
||||
"VOLUME_VALUE": volume_,
|
||||
"PIN_VALUE": panning_,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -319,24 +353,46 @@ def midi_msgs_to_minenote_using_kami_respack(
|
||||
volume_processing_method_: Callable[[float], float],
|
||||
panning_processing_method_: FittingFunctionType,
|
||||
note_table_replacement: Dict[str, str] = {},
|
||||
lyric_line: str = "",
|
||||
) -> MineNote:
|
||||
"""
|
||||
将Midi信息转为我的世界音符对象
|
||||
:param inst_: int 乐器编号
|
||||
:param note_: int 音高编号(音符编号)
|
||||
:param percussive_: bool 是否作为打击乐器启用
|
||||
:param volume_: int 音量
|
||||
:param velocity_: int 力度
|
||||
:param panning_: int 声相偏移
|
||||
:param start_time_: int 音符起始时间(微秒)
|
||||
:param duration_: int 音符持续时间(微秒)
|
||||
:param play_speed: float 曲目播放速度
|
||||
:param midi_reference_table: Dict[int, str] 转换对照表
|
||||
:param volume_processing_method_: Callable[[float], float] 音量处理函数
|
||||
:param panning_processing_method_: Callable[[float], float] 立体声相偏移处理函数
|
||||
:param note_table_replacement: Dict[str, str] 音符替换表,定义 Minecraft 音符字串的替换
|
||||
将Midi信息转为我的世界音符对象,使用神羽资源包兼容格式
|
||||
|
||||
:return MineNote我的世界音符对象
|
||||
Parameters
|
||||
------------
|
||||
inst_: int
|
||||
乐器编号
|
||||
note_: int
|
||||
音高编号(音符编号)
|
||||
percussive_: bool
|
||||
是否作为打击乐器启用
|
||||
volume_: int
|
||||
音量
|
||||
velocity_: int
|
||||
力度
|
||||
panning_: int
|
||||
声相偏移
|
||||
start_time_: int
|
||||
音符起始时间(微秒)
|
||||
duration_: int
|
||||
音符持续时间(微秒)
|
||||
play_speed: float
|
||||
曲目播放速度
|
||||
midi_reference_table: Dict[int, str]
|
||||
转换对照表
|
||||
volume_processing_method_: Callable[[float], float]
|
||||
音量处理函数
|
||||
panning_processing_method_: Callable[[float], float]
|
||||
立体声相偏移处理函数
|
||||
note_table_replacement: Dict[str, str]
|
||||
音符替换表,定义 Minecraft 音符字串的替换
|
||||
lyric_line: str
|
||||
该音符的歌词
|
||||
|
||||
Returns
|
||||
---------
|
||||
MineNote
|
||||
我的世界音符对象
|
||||
"""
|
||||
|
||||
using_original = False
|
||||
@ -371,6 +427,7 @@ def midi_msgs_to_minenote_using_kami_respack(
|
||||
"USING_ORIGINAL_SOUND": using_original, # 判断 extra_information 中是否有 USING_ORIGINAL_SOUND 键是判断是否使用神羽资源包解析的一个显著方法
|
||||
"INST_VALUE": note_ if percussive_ else inst_,
|
||||
"NOTE_VALUE": inst_ if percussive_ else note_,
|
||||
"LYRIC_TEXT": lyric_line,
|
||||
"VOLUME_VALUE": volume_,
|
||||
"PIN_VALUE": panning_,
|
||||
},
|
||||
|
33
test_future_lyric.py
Normal file
33
test_future_lyric.py
Normal file
@ -0,0 +1,33 @@
|
||||
import Musicreater.experiment
|
||||
import Musicreater.plugin
|
||||
import Musicreater.plugin.mcstructfile
|
||||
|
||||
msct = Musicreater.experiment.FutureMidiConvertLyricSupport.from_midi_file(
|
||||
input("midi路径:"), old_exe_format=False
|
||||
)
|
||||
|
||||
opt = input("输出路径:")
|
||||
|
||||
# print(
|
||||
# "乐器使用情况",
|
||||
# )
|
||||
|
||||
# for name in sorted(
|
||||
# set(
|
||||
# [
|
||||
# n.split(".")[0].replace("c", "").replace("d", "")
|
||||
# for n in msct.note_count_per_instrument.keys()
|
||||
# ]
|
||||
# )
|
||||
# ):
|
||||
# print("\t", name, flush=True)
|
||||
|
||||
print(
|
||||
"\n输出:",
|
||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||
msct,
|
||||
opt,
|
||||
# Musicreater.plugin.ConvertConfig(input("输出路径:"),),
|
||||
max_height=32,
|
||||
),
|
||||
)
|
Reference in New Issue
Block a user