From 95c0ff1b4790ec2b5bcc1c48df83f39b546974f2 Mon Sep 17 00:00:00 2001
From: EillesWan
Date: Mon, 4 Mar 2024 00:04:05 +0800
Subject: [PATCH] =?UTF-8?q?2.0.0=E5=85=A8=E6=96=B0=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=EF=BC=8C=E6=9B=B4=E5=A5=BD=E7=9A=84=E4=BB=A3=E7=A0=81=E7=BB=84?=
=?UTF-8?q?=E7=BB=87=E5=BD=A2=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Musicreater/__init__.py | 7 +-
Musicreater/constants.py | 44 +-
Musicreater/exceptions.py | 8 +
Musicreater/experiment.py | 32 +-
Musicreater/main.py | 544 ++++++++++++--------
Musicreater/plugin/addonpack/main.py | 10 +-
Musicreater/plugin/bdx.py | 4 +-
Musicreater/plugin/bdxfile/main.py | 26 +-
Musicreater/plugin/main.py | 16 +-
Musicreater/plugin/mcstructfile/__init__.py | 6 +-
Musicreater/plugin/mcstructfile/main.py | 23 +-
Musicreater/plugin/mcstructure.py | 6 +-
Musicreater/plugin/noteblock.py | 2 +-
Musicreater/plugin/schematic.py | 2 +-
Musicreater/plugin/websocket/main.py | 22 +-
Musicreater/subclass.py | 223 +++++++-
Musicreater/utils.py | 189 +++++--
README.md | 6 +-
README_EN.md | 4 +-
RSMC_test.py | 8 -
example.py | 43 +-
example_futureFunction.py | 2 +-
setup.py | 2 +-
23 files changed, 815 insertions(+), 414 deletions(-)
delete mode 100644 RSMC_test.py
diff --git a/Musicreater/__init__.py b/Musicreater/__init__.py
index c0f6df2..b3efed4 100644
--- a/Musicreater/__init__.py
+++ b/Musicreater/__init__.py
@@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
-__version__ = "1.8"
-__vername__ = "音调总体偏移的处理支持"
+__version__ = "2.0.0-alpha"
+__vername__ = "全新组织架构"
__author__ = (
("金羿", "Eilles Wan"),
("诸葛亮与八卦阵", "bgArray"),
@@ -31,7 +31,8 @@ __all__ = [
"MidiConvert",
# 附加类
"SingleNote",
- "SingleCommand",
+ "MineNote",
+ "MineCommand",
"SingleNoteBox",
# "TimeStamp", 未来功能
# 默认值
diff --git a/Musicreater/constants.py b/Musicreater/constants.py
index 31f3074..9d3772c 100644
--- a/Musicreater/constants.py
+++ b/Musicreater/constants.py
@@ -414,28 +414,28 @@ MC_INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
# Midi对MC通用对照表
-MM_INSTRUMENT_RANGE_TABLE: Dict[str, Tuple[int, int]] = {
- "note.harp": (42, 66),
- "note.pling": (42, 66),
- "note.guitar": (30, 54),
- "note.iron_xylophone": (42, 66),
- "note.bell": (66, 90),
- "note.xylophone": (66, 90),
- "note.chime": (66, 90),
- "note.banjo": (42, 66),
- "note.flute": (54, 78),
- "note.bass": (18, 42),
- "note.snare": (-1, 128), # 实际上是 0~127
- "note.didgeridoo": (18, 42),
- "mob.zombie.wood": (-1, 128),
- "note.bit": (42, 66),
- "note.hat": (-1, 128),
- "note.bd": (-1, 128),
- "note.basedrum": (-1, 128),
- "firework.blast": (-1, 128),
- "firework.twinkle": (-1, 128),
- "fire.ignite": (-1, 128),
- "note.cow_bell": (54, 78),
+MM_INSTRUMENT_RANGE_TABLE: Dict[str, Tuple[Tuple[int, int], int]] = {
+ "note.harp": ((42, 66), 54),
+ "note.pling": ((42, 66), 54),
+ "note.guitar": ((30, 54), 42),
+ "note.iron_xylophone": ((42, 66), 54),
+ "note.bell": ((66, 90), 78),
+ "note.xylophone": ((66, 90), 78),
+ "note.chime": ((66, 90), 78),
+ "note.banjo": ((42, 66), 54),
+ "note.flute": ((54, 78), 66),
+ "note.bass": ((18, 42), 30),
+ "note.snare": ((-1, 128), 0), # 实际上是 0~127
+ "note.didgeridoo": ((18, 42), 30),
+ "mob.zombie.wood": ((-1, 128), 0),
+ "note.bit": ((42, 66), 54),
+ "note.hat": ((-1, 128), 0),
+ "note.bd": ((-1, 128), 0),
+ "note.basedrum": ((-1, 128), 0),
+ "firework.blast": ((-1, 128), 0),
+ "firework.twinkle": ((-1, 128), 0),
+ "fire.ignite": ((-1, 128), 0),
+ "note.cow_bell": ((54, 78), 66),
}
"""不同乐器的音域偏离对照表"""
diff --git a/Musicreater/exceptions.py b/Musicreater/exceptions.py
index cf39919..70f5774 100644
--- a/Musicreater/exceptions.py
+++ b/Musicreater/exceptions.py
@@ -115,3 +115,11 @@ class ZeroSpeedError(ZeroDivisionError):
def __init__(self, *args):
"""以0作为播放速度的错误"""
super().__init__("播放速度为0", *args)
+
+
+class IllegalMinimumVolumeError(ValueError):
+ """最小播放音量有误的错误"""
+
+ def __init__(self, *args):
+ """最小播放音量错误"""
+ super().__init__("最小播放音量超出范围", *args)
\ No newline at end of file
diff --git a/Musicreater/experiment.py b/Musicreater/experiment.py
index 43ef3c5..6d267a6 100644
--- a/Musicreater/experiment.py
+++ b/Musicreater/experiment.py
@@ -95,19 +95,13 @@ class FutureMidiConvertM4(MidiConvert):
def to_command_list_in_delay(
self,
- max_volume: float = 1.0,
- speed: float = 1.0,
player_selector: str = "@a",
- ) -> Tuple[List[SingleCommand], int, int]:
+ ) -> Tuple[List[MineCommand], int, int]:
"""
将midi转换为我的世界命令列表,并输出每个音符之后的延迟
Parameters
----------
- max_volume: float
- 最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
- speed: float
- 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
player_selector: str
玩家选择器,默认为`@a`
@@ -116,17 +110,13 @@ class FutureMidiConvertM4(MidiConvert):
tuple( list[SingleCommand,...], int音乐时长游戏刻, int最大同时播放的指令数量 )
"""
- if speed == 0:
- raise ZeroSpeedError("播放速度仅可为(0,1]范围内的正实数")
- max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
-
- notes_list: List[SingleNote] = []
+ notes_list: List[MineNote] = []
# 此处 我们把通道视为音轨
for channel in self.channels.values():
for note in channel:
note.set_info(
- note_to_command_parameters(
+ single_note_to_note_parameters(
note,
(
self.percussion_note_referrence_table
@@ -160,7 +150,7 @@ class FutureMidiConvertM4(MidiConvert):
max_multi = max(max_multi, multi)
multi = 0
self.music_command_list.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(player_selector)
+ r"playsound {} @s ^ ^ ^{} {} {}".format(*note.extra_info),
tick_delay=tickdelay,
@@ -173,8 +163,7 @@ class FutureMidiConvertM4(MidiConvert):
)
delaytime_previous = delaytime_now
- self.music_tick_num = round(notes_list[-1].start_time / speed / 50)
- return self.music_command_list, self.music_tick_num, max_multi + 1
+ return self.music_command_list, round(notes_list[-1].start_time / speed / 50), max_multi + 1
class FutureMidiConvertM5(MidiConvert):
@@ -267,7 +256,7 @@ class FutureMidiConvertM5(MidiConvert):
max_volume: float = 1.0,
speed: float = 1.0,
player_selector: str = "@a",
- ) -> Tuple[List[SingleCommand], int]:
+ ) -> Tuple[List[MineCommand], int]:
"""
使用金羿的转换思路,使用同刻偏移算法优化音感后,将midi转换为我的世界命令列表,并输出每个音符之后的延迟
@@ -314,11 +303,11 @@ class FutureMidiConvertM5(MidiConvert):
elif msg[0] == "NoteS":
soundID = (
- midi_inst_to_mc_sould(
+ midi_inst_to_mc_sound(
msg[1], MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE
)
if SpecialBits
- else midi_inst_to_mc_sould(
+ else midi_inst_to_mc_sound(
InstID, MM_CLASSIC_PITCHED_INSTRUMENT_TABLE
)
)
@@ -354,7 +343,7 @@ class FutureMidiConvertM5(MidiConvert):
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
- SingleCommand(
+ MineCommand(
tracks[all_ticks[i]][j],
tick_delay=(
(
@@ -402,8 +391,7 @@ class FutureMidiConvertM5(MidiConvert):
)
self.music_command_list = results
- self.music_tick_num = max(all_ticks)
- return results, self.music_tick_num
+ return results, max(all_ticks)
class FutureMidiConvertM6(MidiConvert):
diff --git a/Musicreater/main.py b/Musicreater/main.py
index 4fa6b74..8bf0720 100644
--- a/Musicreater/main.py
+++ b/Musicreater/main.py
@@ -3,9 +3,9 @@
"""
音·创 (Musicreater)
-是一款免费开源的针对《我的世界》的midi音乐转换库
+一款免费开源的针对《我的世界》音乐的支持库
Musicreater (音·创)
-A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
+A free open source library used for **Minecraft** musics.
版权所有 © 2024 音·创 开发者
Copyright © 2024 all the developers of Musicreater
@@ -19,10 +19,10 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库根目录下的 License.md
-# BUG退散!BUG退散! BUG退散!BUG退散!
-# 异常、错误作乱之时 異常、誤りが、困った時は
-# 二六字组!万国码合!二六字组!万国码合! グループ!コード#!グループ!コード#!
-# 赶快呼叫 程序员!Let's Go! 直ぐに呼びましょプログラマ レッツゴー!
+# BUG退散!BUG退散! BUG退散!BUG退散! BUG retreat! BUG retreat!
+# 异常与错误作乱之时 異常、誤りが、困った時は Abnormalities and errors are causing chaos
+# 二六字组!万国码合!二六字组!万国码合! グループ!コード#!グループ!コード#! Words combine! Unicode unite!
+# 赶快呼叫 程序员!Let's Go! 直ぐに呼びましょプログラマ レッツゴー! Hurry to call the programmer! Let's Go!
import math
@@ -84,49 +84,192 @@ class MusicSequence:
"""
music_name: str
- """Midi乐曲名"""
+ """乐曲名"""
- channels: NoteChannelType
+ channels: MineNoteChannelType
"""频道信息字典"""
+ total_note_count: int
+ """音符总数"""
+
+ used_instrument: List[str]
+ """所使用的乐器"""
+
+ minium_volume: float
+ """乐曲最小音量"""
+
+ music_deviation: float
+ """乐曲音调偏移"""
+
def __init__(
self,
name_of_music: str,
- channels_of_notes: NoteChannelType,
+ channels_of_notes: MineNoteChannelType,
+ music_note_count: Optional[int] = None,
+ used_instrument_of_music: Optional[List[str]] = None,
+ minium_volume_of_music: float = 0.1,
+ deviation: Optional[float] = None,
) -> None:
+ """
+ 《我的世界》音符序列类
+
+ Paramaters
+ ==========
+ name_of_music: str
+ 乐曲名称
+ channels_of_notes: MineNoteChannelType
+ 音乐音轨
+ minium_volume_of_music: float
+ 音乐最小音量(0,1]
+ """
+
+ if minium_volume_of_music > 1 or minium_volume_of_music <= 0:
+ raise IllegalMinimumVolumeError(
+ "自订的最小音量参数错误:{},应在 (0,1] 范围内。".format(
+ minium_volume_of_music
+ )
+ )
+ # max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
+
self.music_name = name_of_music
self.channels = channels_of_notes
+ self.minium_volume = minium_volume_of_music
+
+ if used_instrument_of_music is None or music_note_count is None:
+ kp = [i.sound_name for j in self.channels.values() for i in j]
+ self.total_note_count = (
+ len(kp) if music_note_count is None else music_note_count
+ )
+ self.used_instrument = (
+ list(set(kp))
+ if used_instrument_of_music is None
+ else used_instrument_of_music
+ )
+
+ self.music_deviation = (
+ self.guess_deviation(
+ self.total_note_count,
+ len(self.used_instrument),
+ music_channels=self.channels,
+ )
+ if deviation is None
+ else deviation
+ )
@classmethod
def from_mido(
cls,
mido_file: mido.MidiFile,
- midi_music_name,
- default_tempo: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
+ midi_music_name: str,
mismatch_error_ignorance: bool = True,
+ speed_multiplier: float = 1,
+ pitched_note_referance_table: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
+ percussion_note_referance_table: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
+ minium_vol: float = 0.1,
+ volume_processing_function: FittingFunctionType = natural_curve,
+ default_tempo: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
+ devation_guess_enabled: bool = True,
):
-
- return cls(
- midi_music_name,
+ note_channels, note_count_total, inst_note_count, qualified_inst_note_count = (
cls.to_music_note_channels(
midi=mido_file,
+ speed=speed_multiplier,
+ pitched_note_rtable=pitched_note_referance_table,
+ percussion_note_rtable=percussion_note_referance_table,
default_tempo_value=default_tempo,
+ vol_processing_function=volume_processing_function,
ignore_mismatch_error=mismatch_error_ignorance,
+ )
+ )
+ return cls(
+ name_of_music=midi_music_name,
+ channels_of_notes=note_channels,
+ music_note_count=note_count_total,
+ used_instrument_of_music=list(inst_note_count.keys()),
+ minium_volume_of_music=minium_vol,
+ deviation=(
+ cls.guess_deviation(
+ note_count_total,
+ len(inst_note_count),
+ inst_note_count,
+ qualified_inst_note_count,
+ )
+ if devation_guess_enabled
+ else 0
),
)
+ def set_min_volume(self, volume_value: int):
+ self.minium_volume = volume_value
+
def set_deviation(self, deviation_value: int):
self.music_deviation = deviation_value
def rename_music(self, new_name: str):
self.music_name = new_name
+ def add_note(self, channel_no: int, note: MineNote, is_sort: bool = False):
+ self.channels[channel_no].append(note)
+ self.total_note_count += 1
+ if is_sort:
+ self.channels[channel_no].sort(key=lambda note: note.start_tick)
+
+ @staticmethod
+ def guess_deviation(
+ total_note_count: int,
+ total_instrument_count: int,
+ note_count_per_instruments: Optional[Dict[str, int]] = None,
+ qualified_note_count_per_instruments: Optional[Dict[str, int]] = None,
+ music_channels: Optional[MineNoteChannelType] = None,
+ ) -> float:
+ if (
+ note_count_per_instruments is None
+ or qualified_note_count_per_instruments is None
+ ):
+ if music_channels is None:
+ raise ValueError("参数不足,算逑!")
+ note_count_per_instruments = {}
+ qualified_note_count_per_instruments = {}
+ for this_note in [k for j in music_channels.values() for k in j]:
+ if this_note.sound_name in note_count_per_instruments.keys():
+ note_count_per_instruments[this_note.sound_name] += 1
+ qualified_note_count_per_instruments[
+ this_note.sound_name
+ ] += is_note_in_diapason(this_note)
+ else:
+ note_count_per_instruments[this_note.sound_name] = 1
+ qualified_note_count_per_instruments[this_note.sound_name] = int(
+ is_note_in_diapason(this_note)
+ )
+ return (
+ sum(
+ [
+ (
+ (
+ MM_INSTRUMENT_RANGE_TABLE[inst][-1]
+ * note_count
+ / total_note_count
+ - MM_INSTRUMENT_RANGE_TABLE[inst][-1]
+ )
+ * (note_count - qualified_note_count_per_instruments[inst])
+ )
+ for inst, note_count in note_count_per_instruments.items()
+ ]
+ )
+ / total_instrument_count
+ / total_note_count
+ )
+
@staticmethod
def to_music_note_channels(
midi: mido.MidiFile,
- default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
ignore_mismatch_error: bool = True,
- ) -> NoteChannelType:
+ speed: float = 1.0,
+ pitched_note_rtable: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
+ percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
+ default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
+ vol_processing_function: FittingFunctionType = natural_curve,
+ ) -> Tuple[MineNoteChannelType, int, Dict[str, int], Dict[str, int]]:
"""
将midi解析并转换为频道音符字典
@@ -136,14 +279,20 @@ class MusicSequence:
Dict[int,List[SingleNote,]]
"""
+ if speed == 0:
+ raise ZeroSpeedError("播放速度为 0 ,其需要(0,1]范围内的实数。")
+
# if midi is None:
# raise MidiUnboundError(
# "Midi参量为空。你是否正在使用的是一个由 copy_important 生成的MidiConvert对象?这是不可复用的。"
# )
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
- midi_channels: NoteChannelType = empty_midi_channels(staff=[])
+ midi_channels: MineNoteChannelType = empty_midi_channels(staff=[])
tempo = default_tempo_value
+ note_count = 0
+ note_count_per_instruments: Dict[str, int] = {}
+ qualified_note_count_per_instruments: Dict[str, int] = {}
# 我们来用通道统计音乐信息
# 但是是用分轨的思路的
@@ -205,27 +354,47 @@ class MusicSequence:
(msg.note, channel_program[msg.channel])
)
note_queue_B[msg.channel].remove((_velocity, _ms))
+
midi_channels[msg.channel].append(
- SingleNote(
- instrument=msg.note,
- pitch=channel_program[msg.channel],
- velocity=_velocity,
- startime=_ms,
- lastime=microseconds - _ms,
- track_number=track_no,
- is_percussion=True,
- )
- if msg.channel == 9
- else SingleNote(
- instrument=channel_program[msg.channel],
- pitch=msg.note,
- velocity=_velocity,
- startime=_ms,
- lastime=microseconds - _ms,
- track_number=track_no,
- is_percussion=False,
+ that_note := midi_msgs_to_minenote(
+ inst_=(
+ msg.note
+ if msg.channel == 9
+ else channel_program[msg.channel]
+ ),
+ note_=(
+ channel_program[msg.channel]
+ if msg.channel == 9
+ else msg.note
+ ),
+ velocity_=_velocity,
+ start_time_=_ms,
+ duration_=microseconds - _ms,
+ track_no_=track_no,
+ percussive_=(msg.channel == 9),
+ play_speed=speed,
+ midi_reference_table=(
+ percussion_note_rtable
+ if msg.channel == 9
+ else pitched_note_rtable
+ ),
+ volume_processing_method_=vol_processing_function,
)
)
+ note_count += 1
+ if (
+ that_note.sound_name
+ in note_count_per_instruments.keys()
+ ):
+ note_count_per_instruments[that_note.sound_name] += 1
+ qualified_note_count_per_instruments[
+ that_note.sound_name
+ ] += is_note_in_diapason(that_note)
+ else:
+ note_count_per_instruments[that_note.sound_name] = 1
+ qualified_note_count_per_instruments[
+ that_note.sound_name
+ ] = int(is_note_in_diapason(that_note))
else:
if ignore_mismatch_error:
print(
@@ -254,12 +423,17 @@ class MusicSequence:
del tempo
channels = dict(
[
- (channel_no, sorted(channel_notes, key=lambda note: note.start_time))
+ (channel_no, sorted(channel_notes, key=lambda note: note.start_tick))
for channel_no, channel_notes in midi_channels.items()
]
)
- return channels
+ return (
+ channels,
+ note_count,
+ note_count_per_instruments,
+ qualified_note_count_per_instruments,
+ )
class MidiConvert(MusicSequence):
@@ -267,42 +441,31 @@ class MidiConvert(MusicSequence):
将Midi文件转换为我的世界内容
"""
- pitched_note_reference_table: MidiInstrumentTableType
- """乐音乐器Midi-MC对照表"""
-
- percussion_note_referrence_table: MidiInstrumentTableType
- """打击乐器Midi-MC对照表"""
-
- volume_processing_function: FittingFunctionType
- """音量处理函数"""
-
enable_old_exe_format: bool
"""是否启用旧版execute指令格式"""
execute_cmd_head: str
"""execute指令头部"""
- music_command_list: List[SingleCommand]
+ music_command_list: List[MineCommand]
"""音乐指令列表"""
- music_tick_num: int
- """音乐总延迟"""
-
- progress_bar_command: List[SingleCommand]
+ progress_bar_command: List[MineCommand]
"""进度条指令列表"""
- music_deviation: int
- """音乐音调总偏移"""
-
- def __init__(
- self,
+ @classmethod
+ def from_mido_obj(
+ cls,
midi_obj: mido.MidiFile,
midi_name: str,
- deviation: Union[int, Literal[None]] = 0,
ignore_mismatch_error: bool = True,
- enable_old_exe_format: bool = False,
+ playment_speed: float = 1,
+ default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
pitched_note_rtable: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
+ enable_devation_guess: bool = True,
+ enable_old_exe_format: bool = False,
+ minium_volume: float = 0.1,
vol_processing_function: FittingFunctionType = natural_curve,
):
"""
@@ -322,40 +485,42 @@ class MidiConvert(MusicSequence):
打击乐器Midi-MC对照表
"""
- super(MidiConvert, self).from_mido(
- midi_obj,
- midi_name,
- mismatch_error_ignorance=ignore_mismatch_error,
- )
+ cls.enable_old_exe_format: bool = enable_old_exe_format
- self.music_deviation = (
- self.guess_deviation() if deviation is None else deviation
- )
-
- self.enable_old_exe_format: bool = enable_old_exe_format
-
- self.execute_cmd_head = (
+ cls.execute_cmd_head = (
"execute {} ~ ~ ~ "
if enable_old_exe_format
else "execute as {} at @s positioned ~ ~ ~ run "
)
- self.pitched_note_reference_table = pitched_note_rtable
- self.percussion_note_referrence_table = percussion_note_rtable
- self.volume_processing_function = vol_processing_function
+ cls.progress_bar_command = cls.music_command_list = []
+ cls.channels = {}
- self.progress_bar_command = self.music_command_list = []
- self.channels = {}
- self.music_tick_num = 0
+ return cls.from_mido(
+ mido_file=midi_obj,
+ midi_music_name=midi_name,
+ speed_multiplier=playment_speed,
+ pitched_note_referance_table=pitched_note_rtable,
+ percussion_note_referance_table=percussion_note_rtable,
+ minium_vol=minium_volume,
+ volume_processing_function=vol_processing_function,
+ default_tempo=default_tempo_value,
+ devation_guess_enabled=enable_devation_guess,
+ mismatch_error_ignorance=ignore_mismatch_error,
+ )
@classmethod
def from_midi_file(
cls,
midi_file_path: str,
- ignore_mismatch_error: bool = True,
- old_exe_format: bool = False,
+ mismatch_error_ignorance: bool = True,
+ play_speed: float = 1,
+ default_tempo: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
pitched_note_table: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_table: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
+ devation_guess_enabled: bool = True,
+ old_exe_format: bool = False,
+ min_volume: float = 0.1,
vol_processing_func: FittingFunctionType = natural_curve,
):
"""
@@ -363,14 +528,19 @@ class MidiConvert(MusicSequence):
Parameters
----------
- midi_file: str
+ midi_file_path: str
midi文件地址
- enable_old_exe_format: bool
- 是否启用旧版(≤1.19)指令格式,默认为否
+
+ speed: float
+ 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
pitched_note_table: Dict[int, Tuple[str, int]]
乐音乐器Midi-MC对照表
percussion_note_table: Dict[int, Tuple[str, int]]
打击乐器Midi-MC对照表
+ enable_old_exe_format: bool
+ 是否启用旧版(≤1.19)指令格式,默认为否
+ min_volume: float
+ 最小播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值
"""
midi_music_name = os.path.splitext(os.path.basename(midi_file_path))[0].replace(
@@ -379,18 +549,21 @@ class MidiConvert(MusicSequence):
"""文件名,不含路径且不含后缀"""
try:
- return cls(
- mido.MidiFile(
+ return cls.from_mido_obj(
+ midi_obj=mido.MidiFile(
midi_file_path,
clip=True,
),
- midi_music_name,
- None,
- old_exe_format,
- ignore_mismatch_error,
- pitched_note_table,
- percussion_note_table,
- vol_processing_func,
+ midi_name=midi_music_name,
+ ignore_mismatch_error=mismatch_error_ignorance,
+ playment_speed=play_speed,
+ default_tempo_value=default_tempo,
+ pitched_note_rtable=pitched_note_table,
+ percussion_note_rtable=percussion_note_table,
+ enable_devation_guess=devation_guess_enabled,
+ enable_old_exe_format=old_exe_format,
+ minium_volume=min_volume,
+ vol_processing_function=vol_processing_func,
)
except (ValueError, TypeError) as E:
raise MidiDestroyedError(f"文件{midi_file_path}损坏:{E}")
@@ -400,17 +573,12 @@ class MidiConvert(MusicSequence):
# ……真的那么重要吗
# 我又几曾何时,知道祂真的会抛下我
- def guess_deviation(self) -> int:
-
- # 等我想想看
- return 0
-
def form_progress_bar(
self,
max_score: int,
scoreboard_name: str,
progressbar_style: ProgressBarStyle = DEFAULT_PROGRESSBAR_STYLE,
- ) -> List[SingleCommand]:
+ ) -> List[MineCommand]:
"""
生成进度条
@@ -446,7 +614,7 @@ class MidiConvert(MusicSequence):
perEach = max_score / pgs_style.count("_")
"""每个进度条代表的分值"""
- result: List[SingleCommand] = []
+ result: List[MineCommand] = []
if r"%^s" in pgs_style:
pgs_style = pgs_style.replace(r"%^s", str(max_score))
@@ -457,7 +625,7 @@ class MidiConvert(MusicSequence):
sbn_pc = scoreboard_name[:2]
if r"%%%" in pgs_style:
result.append(
- SingleCommand(
+ MineCommand(
'scoreboard objectives add {}PercT dummy "百分比计算"'.format(
sbn_pc
),
@@ -465,7 +633,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -476,7 +644,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -485,7 +653,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -496,7 +664,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -507,7 +675,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -524,7 +692,7 @@ class MidiConvert(MusicSequence):
if r"%%t" in pgs_style:
result.append(
- SingleCommand(
+ MineCommand(
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(
sbn_pc
),
@@ -532,7 +700,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(
sbn_pc
),
@@ -540,7 +708,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -549,7 +717,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -559,7 +727,7 @@ class MidiConvert(MusicSequence):
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -570,7 +738,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -581,7 +749,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -593,7 +761,7 @@ class MidiConvert(MusicSequence):
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -605,7 +773,7 @@ class MidiConvert(MusicSequence):
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
@@ -642,7 +810,7 @@ class MidiConvert(MusicSequence):
)
)
result.append(
- SingleCommand(
+ MineCommand(
self.execute_cmd_head.format(
r"@a[scores={"
+ scoreboard_name
@@ -658,20 +826,20 @@ class MidiConvert(MusicSequence):
if r"%%%" in pgs_style:
result.append(
- SingleCommand(
+ MineCommand(
"scoreboard objectives remove {}PercT".format(sbn_pc),
annotation="移除临时百分比变量",
)
)
if r"%%t" in pgs_style:
result.append(
- SingleCommand(
+ MineCommand(
"scoreboard objectives remove {}TMinT".format(sbn_pc),
annotation="移除临时分变量",
)
)
result.append(
- SingleCommand(
+ MineCommand(
"scoreboard objectives remove {}TSecT".format(sbn_pc),
annotation="移除临时秒变量",
)
@@ -683,9 +851,7 @@ class MidiConvert(MusicSequence):
def to_command_list_in_score(
self,
scoreboard_name: str = "mscplay",
- max_volume: float = 1.0,
- speed: float = 1.0,
- ) -> Tuple[List[List[SingleCommand]], int, int]:
+ ) -> Tuple[List[List[MineCommand]], int, int]:
"""
将midi转换为我的世界命令列表
@@ -693,20 +859,12 @@ class MidiConvert(MusicSequence):
----------
scoreboard_name: str
我的世界的计分板名称
- max_volume: float
- 最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放
- speed: float
- 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
Returns
-------
tuple( list[list[SingleCommand指令,... ],... ], int指令数量, int音乐时长游戏刻 )
"""
- if speed == 0:
- raise ZeroSpeedError("播放速度仅可为(0,1]范围内的正实数")
- max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
-
command_channels = []
command_amount = 0
max_score = 0
@@ -720,59 +878,44 @@ class MidiConvert(MusicSequence):
this_channel = []
for note in channel:
- score_now = round(note.start_time / float(speed) / 50)
- max_score = max(max_score, score_now)
+ max_score = max(max_score, note.start_tick)
(
mc_sound_ID,
- mc_distance_volume,
+ relative_coordinates,
volume_percentage,
mc_pitch,
- ) = note_to_command_parameters(
+ ) = minenote_to_command_paramaters(
note,
- (
- self.percussion_note_referrence_table
- if note.percussive
- else self.pitched_note_reference_table
- ),
- deviation=self.music_deviation,
- volume_percentage=(
- (max_volume) if note.track_no == 0 else (max_volume * 0.9)
- ),
- volume_processing_method=self.volume_processing_function,
+ pitch_deviation=self.music_deviation,
)
this_channel.append(
- SingleCommand(
+ MineCommand(
(
self.execute_cmd_head.format(
- "@a[scores=({}={})]".format(scoreboard_name, score_now)
+ "@a[scores=({}={})]".format(
+ scoreboard_name, note.start_tick
+ )
.replace("(", r"{")
.replace(")", r"}")
)
- + (
- r"playsound {} @s ^ ^ ^{} {}".format(
- mc_sound_ID, mc_distance_volume, volume_percentage
- )
- if note.percussive
- else r"playsound {} @s ^ ^ ^{} {} {}".format(
- mc_sound_ID,
- mc_distance_volume,
- volume_percentage,
- mc_pitch,
- )
+ + r"playsound {} @s ^{} ^{} ^{} {} {} {}".format(
+ mc_sound_ID,
+ *relative_coordinates,
+ volume_percentage,
+ 1.0 if note.percussive else mc_pitch,
+ self.minium_volume,
)
),
annotation=(
- "在{}播放{}%的{}噪音".format(
- mctick2timestr(score_now),
- max_volume * 100,
+ "在{}播放噪音{}".format(
+ mctick2timestr(note.start_tick),
mc_sound_ID,
)
if note.percussive
- else "在{}播放{}%的{}乐音".format(
- mctick2timestr(score_now),
- max_volume * 100,
+ else "在{}播放乐音{}".format(
+ mctick2timestr(note.start_tick),
"{}:{:.2f}".format(mc_sound_ID, mc_pitch),
)
),
@@ -785,24 +928,17 @@ class MidiConvert(MusicSequence):
self.music_command_list.extend(this_channel)
command_channels.append(this_channel)
- self.music_tick_num = max_score
return command_channels, command_amount, max_score
def to_command_list_in_delay(
self,
- max_volume: float = 1.0,
- speed: float = 1.0,
player_selector: str = "@a",
- ) -> Tuple[List[SingleCommand], int, int]:
+ ) -> Tuple[List[MineCommand], int, int]:
"""
将midi转换为我的世界命令列表,并输出每个音符之后的延迟
Parameters
----------
- max_volume: float
- 最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
- speed: float
- 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
player_selector: str
玩家选择器,默认为`@a`
@@ -811,25 +947,18 @@ class MidiConvert(MusicSequence):
tuple( list[SingleCommand,...], int音乐时长游戏刻, int最大同时播放的指令数量 )
"""
- if speed == 0:
- raise ZeroSpeedError("播放速度仅可为(0,1]范围内的正实数")
- max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
-
- notes_list: List[SingleNote] = []
+ notes_list: List[MineNote] = sorted(
+ [i for j in self.channels.values() for i in j],
+ key=lambda note: note.start_tick,
+ )
# 此处 我们把通道视为音轨
- for channel in self.channels.values():
- notes_list.extend(channel)
-
- notes_list.sort(key=lambda a: a.start_time)
-
self.music_command_list = []
multi = max_multi = 0
delaytime_previous = 0
for note in notes_list:
- delaytime_now = round(note.start_time / speed / 50)
- if (tickdelay := (delaytime_now - delaytime_previous)) == 0:
+ if (tickdelay := (note.start_tick - delaytime_previous)) == 0:
multi += 1
else:
max_multi = max(max_multi, multi)
@@ -837,68 +966,53 @@ class MidiConvert(MusicSequence):
(
mc_sound_ID,
- mc_distance_volume,
+ relative_coordinates,
volume_percentage,
mc_pitch,
- ) = note_to_command_parameters(
+ ) = minenote_to_command_paramaters(
note,
- (
- self.percussion_note_referrence_table
- if note.percussive
- else self.pitched_note_reference_table
- ),
- deviation=self.music_deviation,
- volume_percentage=(
- (max_volume) if note.track_no == 0 else (max_volume * 0.9)
- ),
- volume_processing_method=self.volume_processing_function,
+ pitch_deviation=self.music_deviation,
)
self.music_command_list.append(
- SingleCommand(
+ MineCommand(
command=(
self.execute_cmd_head.format(player_selector)
- + (
- r"playsound {} @s ^ ^ ^{} {}".format(
- mc_sound_ID, mc_distance_volume, volume_percentage
- )
- if note.percussive
- else r"playsound {} @s ^ ^ ^{} {} {}".format(
- mc_sound_ID,
- mc_distance_volume,
- volume_percentage,
- mc_pitch,
- )
+ + r"playsound {} @s ^{} ^{} ^{} {} {} {}".format(
+ mc_sound_ID,
+ *relative_coordinates,
+ volume_percentage,
+ 1.0 if note.percussive else mc_pitch,
+ self.minium_volume,
)
),
annotation=(
- "在{}播放{}%的{}噪音".format(
- mctick2timestr(delaytime_now),
- max_volume * 100,
+ "在{}播放噪音{}".format(
+ mctick2timestr(note.start_tick),
mc_sound_ID,
)
if note.percussive
- else "在{}播放{}%的{}乐音".format(
- mctick2timestr(delaytime_now),
- max_volume * 100,
+ else "在{}播放乐音{}".format(
+ mctick2timestr(note.start_tick),
"{}:{:.2f}".format(mc_sound_ID, mc_pitch),
)
),
tick_delay=tickdelay,
),
)
- delaytime_previous = delaytime_now
+ delaytime_previous = note.start_tick
- self.music_tick_num = round(notes_list[-1].start_time / speed / 50)
- return self.music_command_list, self.music_tick_num, max_multi + 1
+ return self.music_command_list, notes_list[-1].start_tick, max_multi + 1
def copy_important(self):
- dst = MidiConvert(
+ dst = MidiConvert.from_mido_obj(
midi_obj=mido.MidiFile(),
midi_name=self.music_name,
enable_old_exe_format=self.enable_old_exe_format,
+ pitched_note_rtable={},
+ percussion_note_rtable={},
+ vol_processing_function=lambda a: a,
)
dst.music_command_list = [i.copy() for i in self.music_command_list]
dst.progress_bar_command = [i.copy() for i in self.progress_bar_command]
- dst.music_tick_num = self.music_tick_num
return dst
diff --git a/Musicreater/plugin/addonpack/main.py b/Musicreater/plugin/addonpack/main.py
index f4655b6..5837e5c 100644
--- a/Musicreater/plugin/addonpack/main.py
+++ b/Musicreater/plugin/addonpack/main.py
@@ -56,7 +56,7 @@ def to_addon_pack_in_score(
"""
cmdlist, maxlen, maxscore = midi_cvt.to_command_list_in_score(
- scoreboard_name, data_cfg.volume_ratio, data_cfg.speed_multiplier
+ scoreboard_name=scoreboard_name,
)
# 当文件f夹{self.outputPath}/temp/functions存在时清空其下所有项目,然后创建
@@ -180,9 +180,7 @@ def to_addon_pack_in_delay(
)
command_list, max_delay = midi_cvt.to_command_list_in_delay(
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
- player,
+ player_selector=player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
@@ -377,9 +375,7 @@ def to_addon_pack_in_repeater(
)
command_list, max_delay, max_together = midi_cvt.to_command_list_in_delay(
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
- player,
+ player_selector=player,
)
if not os.path.exists(data_cfg.dist_path):
diff --git a/Musicreater/plugin/bdx.py b/Musicreater/plugin/bdx.py
index 8677164..4f27c0c 100644
--- a/Musicreater/plugin/bdx.py
+++ b/Musicreater/plugin/bdx.py
@@ -18,7 +18,7 @@ Terms & Conditions: License.md in the root directory
from typing import List
from ..constants import x, y, z
-from ..subclass import SingleCommand
+from ..subclass import MineCommand
from .common import bottem_side_length_of_smallest_square_bottom_box
BDX_MOVE_KEY = {
@@ -123,7 +123,7 @@ def form_command_block_in_BDX_bytes(
def commands_to_BDX_bytes(
- commands_list: List[SingleCommand],
+ commands_list: List[MineCommand],
max_height: int = 64,
):
"""
diff --git a/Musicreater/plugin/bdxfile/main.py b/Musicreater/plugin/bdxfile/main.py
index 51c2e72..07f6bec 100644
--- a/Musicreater/plugin/bdxfile/main.py
+++ b/Musicreater/plugin/bdxfile/main.py
@@ -17,7 +17,7 @@ import os
import brotli
from ...main import MidiConvert
-from ...subclass import SingleCommand
+from ...subclass import MineCommand
from ..bdx import (
bdx_move,
commands_to_BDX_bytes,
@@ -61,16 +61,14 @@ def to_BDX_file_in_score(
"""
cmdlist, command_count, max_score = midi_cvt.to_command_list_in_score(
- scoreboard_name, data_cfg.volume_ratio, data_cfg.speed_multiplier
+ scoreboard_name=scoreboard_name,
)
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
with open(
- os.path.abspath(
- os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")
- ),
+ os.path.abspath(os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")),
"w+",
) as f:
f.write("BD@")
@@ -83,7 +81,7 @@ def to_BDX_file_in_score(
midi_cvt.music_command_list
+ (
[
- SingleCommand(
+ MineCommand(
command="scoreboard players reset @a[scores={"
+ scoreboard_name
+ "="
@@ -118,9 +116,7 @@ def to_BDX_file_in_score(
_bytes += cmdBytes
with open(
- os.path.abspath(
- os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")
- ),
+ os.path.abspath(os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")),
"ab+",
) as f:
f.write(brotli.compress(_bytes + b"XE"))
@@ -157,18 +153,14 @@ def to_BDX_file_in_delay(
"""
cmdlist, max_delay = midi_cvt.to_command_list_in_delay(
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
- player,
+ player_selector=player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
with open(
- os.path.abspath(
- os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")
- ),
+ os.path.abspath(os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")),
"w+",
) as f:
f.write("BD@")
@@ -216,9 +208,7 @@ def to_BDX_file_in_delay(
_bytes += cmdBytes
with open(
- os.path.abspath(
- os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")
- ),
+ os.path.abspath(os.path.join(data_cfg.dist_path, f"{midi_cvt.music_name}.bdx")),
"ab+",
) as f:
f.write(brotli.compress(_bytes + b"XE"))
diff --git a/Musicreater/plugin/main.py b/Musicreater/plugin/main.py
index 83d6f94..154af62 100644
--- a/Musicreater/plugin/main.py
+++ b/Musicreater/plugin/main.py
@@ -23,17 +23,11 @@ from ..subclass import DEFAULT_PROGRESSBAR_STYLE, ProgressBarStyle
@dataclass(init=False)
-class ConvertConfig:
+class ConvertConfig: # 必定要改
"""
转换通用设置存储类
"""
- volume_ratio: float
- """音量比例"""
-
- speed_multiplier: float
- """速度倍率"""
-
progressbar_style: Union[ProgressBarStyle, None]
"""进度条样式"""
@@ -43,8 +37,6 @@ class ConvertConfig:
def __init__(
self,
output_path: str,
- volume: float = 1.0,
- speed: float = 1.0,
progressbar: Union[bool, Tuple[str, Tuple[str, str]], ProgressBarStyle] = True,
ignore_progressbar_param_error: bool = False,
):
@@ -67,12 +59,6 @@ class ConvertConfig:
self.dist_path = output_path
"""输出目录"""
- self.volume_ratio = volume
- """音量比例"""
-
- self.speed_multiplier = speed
- """速度倍率"""
-
if progressbar:
# 此处是对于仅有 True 的参数和自定义参数的判断
# 改这一段没🐎
diff --git a/Musicreater/plugin/mcstructfile/__init__.py b/Musicreater/plugin/mcstructfile/__init__.py
index cb43943..4181be5 100644
--- a/Musicreater/plugin/mcstructfile/__init__.py
+++ b/Musicreater/plugin/mcstructfile/__init__.py
@@ -21,4 +21,8 @@ __all__ = [
]
__author__ = (("金羿", "Eilles Wan"),)
-from .main import to_mcstructure_file_in_delay, to_mcstructure_file_in_repeater, to_mcstructure_file_in_score
+from .main import (
+ to_mcstructure_file_in_delay,
+ to_mcstructure_file_in_repeater,
+ to_mcstructure_file_in_score,
+)
diff --git a/Musicreater/plugin/mcstructfile/main.py b/Musicreater/plugin/mcstructfile/main.py
index ad10ffb..37ce215 100644
--- a/Musicreater/plugin/mcstructfile/main.py
+++ b/Musicreater/plugin/mcstructfile/main.py
@@ -17,7 +17,7 @@ from typing import Literal
# from ...exceptions import CommandFormatError
from ...main import MidiConvert
from ..main import ConvertConfig
-from ...subclass import SingleCommand
+from ...subclass import MineCommand
from ..mcstructure import (
COMPABILITY_VERSION_117,
COMPABILITY_VERSION_119,
@@ -58,9 +58,7 @@ def to_mcstructure_file_in_delay(
)
cmd_list, max_delay = midi_cvt.to_command_list_in_delay(
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
- player,
+ player_selector=player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
@@ -116,18 +114,17 @@ def to_mcstructure_file_in_score(
)
cmd_list, cmd_count, max_delay = midi_cvt.to_command_list_in_score(
- scoreboard_name,
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
+ scoreboard_name=scoreboard_name,
)
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
struct, size, end_pos = commands_to_structure(
- midi_cvt.music_command_list+(
+ midi_cvt.music_command_list
+ + (
[
- SingleCommand(
+ MineCommand(
command="scoreboard players reset @a[scores={"
+ scoreboard_name
+ "="
@@ -139,7 +136,9 @@ def to_mcstructure_file_in_score(
]
if auto_reset
else []
- ), max_height - 1, compability_version_=compability_ver
+ ),
+ max_height - 1,
+ compability_version_=compability_ver,
)
with open(
@@ -188,9 +187,7 @@ def to_mcstructure_file_in_repeater(
)
cmd_list, max_delay, max_multiple_cmd = midi_cvt.to_command_list_in_delay(
- data_cfg.volume_ratio,
- data_cfg.speed_multiplier,
- player,
+ player_selector=player,
)
if not os.path.exists(data_cfg.dist_path):
diff --git a/Musicreater/plugin/mcstructure.py b/Musicreater/plugin/mcstructure.py
index 99b5985..9dfa033 100644
--- a/Musicreater/plugin/mcstructure.py
+++ b/Musicreater/plugin/mcstructure.py
@@ -21,7 +21,7 @@ from typing import List, Literal, Tuple
from TrimMCStruct import Block, Structure, TAG_Byte, TAG_Long
from ..constants import x, y, z
-from ..subclass import SingleCommand
+from ..subclass import MineCommand
from .common import bottem_side_length_of_smallest_square_bottom_box
@@ -226,7 +226,7 @@ def form_command_block_in_NBT_struct(
def commands_to_structure(
- commands: List[SingleCommand],
+ commands: List[MineCommand],
max_height: int = 64,
compability_version_: int = COMPABILITY_VERSION_119,
):
@@ -313,7 +313,7 @@ def commands_to_structure(
def commands_to_redstone_delay_structure(
- commands: List[SingleCommand],
+ commands: List[MineCommand],
delay_length: int,
max_multicmd_length: int,
base_block: str = "concrete",
diff --git a/Musicreater/plugin/noteblock.py b/Musicreater/plugin/noteblock.py
index 9465425..5900d37 100644
--- a/Musicreater/plugin/noteblock.py
+++ b/Musicreater/plugin/noteblock.py
@@ -18,7 +18,7 @@ Terms & Conditions: License.md in the root directory
from ..exceptions import NotDefineProgramError, ZeroSpeedError
from ..main import MidiConvert
-from ..subclass import SingleCommand
+from ..subclass import MineCommand
from ..utils import inst_to_sould_with_deviation, perc_inst_to_soundID_withX
# 你以为写完了吗?其实并没有
diff --git a/Musicreater/plugin/schematic.py b/Musicreater/plugin/schematic.py
index 3138e22..54091cf 100644
--- a/Musicreater/plugin/schematic.py
+++ b/Musicreater/plugin/schematic.py
@@ -15,4 +15,4 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
-import nbtschematic
+# import nbtschematic
diff --git a/Musicreater/plugin/websocket/main.py b/Musicreater/plugin/websocket/main.py
index 0e7e986..5ea71ca 100644
--- a/Musicreater/plugin/websocket/main.py
+++ b/Musicreater/plugin/websocket/main.py
@@ -13,17 +13,17 @@ Terms & Conditions: License.md in the root directory
import fcwslib
-from ...main import MidiConvert
+# from ...main import MidiConvert
-from ..main import ConvertConfig
-from ...subclass import SingleCommand
+# from ..main import ConvertConfig
+# from ...subclass import MineCommand
-def open_websocket_server(
- midi_cvt: MidiConvert,
- data_cfg: ConvertConfig,
- player: str = "@a",
- server_dist: str = "localhost",
- server_port: int = 8000,
-):
- wssever = fcwslib.Server(server=server_dist,port=server_port,debug_mode=False)
\ No newline at end of file
+# def open_websocket_server(
+# midi_cvt: MidiConvert,
+# data_cfg: ConvertConfig,
+# player: str = "@a",
+# server_dist: str = "localhost",
+# server_port: int = 8000,
+# ):
+# wssever = fcwslib.Server(server=server_dist,port=server_port,debug_mode=False)
\ No newline at end of file
diff --git a/Musicreater/subclass.py b/Musicreater/subclass.py
index bdd3d59..2baa81f 100644
--- a/Musicreater/subclass.py
+++ b/Musicreater/subclass.py
@@ -18,12 +18,207 @@ Terms & Conditions: License.md in the root directory
from dataclasses import dataclass
-from typing import Any
-from .types import Optional, Any, List, Mapping
+from .types import Optional, Any, List, Mapping, Tuple, Union
from .constants import MC_PERCUSSION_INSTRUMENT_LIST
+@dataclass(init=False)
+class MineNote:
+ """存储单个音符的类"""
+
+ sound_name: str
+ """乐器ID"""
+
+ note_pitch: int
+ """midi音高"""
+
+ velocity: int
+ """响度(力度)"""
+
+ start_tick: int
+ """开始之时 命令刻"""
+
+ duration: int
+ """音符持续时间 命令刻"""
+
+ track_no: int
+ """音符所处的音轨"""
+
+ percussive: bool
+ """是否作为打击乐器启用"""
+
+ position_displacement: Tuple[float, float, float]
+ """声像位移"""
+
+ extra_info: Any
+ """你觉得放什么好?"""
+
+ def __init__(
+ self,
+ mc_sound_name: str,
+ midi_pitch: Optional[int],
+ midi_velocity: int,
+ start_time: int,
+ last_time: int,
+ track_number: int = 0,
+ is_percussion: Optional[bool] = None,
+ 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` 开始之时(命令刻)
+ 注:此处的时间是用从乐曲开始到当前的毫秒数
+ :param last_time:`int` 音符延续时间(命令刻)
+ :param track_number:`int` 音轨编号
+ :param is_percussion:`bool` 是否作为打击乐器
+ :param displacement:`tuple[int,int,int]` 声像位移
+ :param extra_information:`Any` 附加信息"""
+ self.sound_name: str = mc_sound_name
+ """乐器ID"""
+ self.note_pitch: int = 66 if midi_pitch is None else midi_pitch
+ """midi音高"""
+ self.velocity: int = midi_velocity
+ """响度(力度)"""
+ self.start_tick: int = start_time
+ """开始之时 tick"""
+ self.duration: int = last_time
+ """音符持续时间 tick"""
+ self.track_no: int = track_number
+ """音符所处的音轨"""
+
+ self.percussive = (
+ (mc_sound_name in MC_PERCUSSION_INSTRUMENT_LIST)
+ if (is_percussion is None)
+ else is_percussion
+ )
+ """是否为打击乐器"""
+
+ self.position_displacement = (
+ (0, 0, 0) if (displacement is None) else displacement
+ )
+ """声像位移"""
+
+ self.extra_info = extra_information
+
+ # @property
+ # def get_mc_pitch(self,table: Dict[int, Tuple[str, int]]) -> float:
+ # self.mc_sound_ID, _X = inst_to_sould_with_deviation(self.inst,table,"note.bd" if self.percussive else "note.flute",)
+ # return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
+
+ def set_info(self, sth: Any):
+ """设置附加信息"""
+ self.extra_info = sth
+
+ def __str__(self, is_displacement: bool = False, is_track: bool = False):
+ return "{}Note(Instrument = {}, {}Velocity = {}, StartTick = {}, Duration = {}{}{})".format(
+ "Percussive" if self.percussive else "",
+ self.sound_name,
+ "" if self.percussive else "NotePitch = {}, ".format(self.note_pitch),
+ self.start_tick,
+ self.duration,
+ ", Track = {}".format(self.track_no) if is_track else "",
+ (
+ ", PositionDisplacement = {}".format(self.position_displacement)
+ if is_displacement
+ else ""
+ ),
+ )
+
+ def tuplize(self, is_displacement: bool = False, is_track: bool = False):
+ tuplized = self.__tuple__()
+ return (
+ tuplized[:-2]
+ + ((tuplized[-2],) if is_track else ())
+ + ((tuplized[-1],) if is_displacement else ())
+ )
+
+ def __list__(self) -> List:
+ return (
+ [
+ self.percussive,
+ self.sound_name,
+ self.velocity,
+ self.start_tick,
+ self.duration,
+ self.track_no,
+ self.position_displacement,
+ ]
+ if self.percussive
+ else [
+ self.percussive,
+ self.sound_name,
+ self.note_pitch,
+ self.velocity,
+ self.start_tick,
+ self.duration,
+ self.track_no,
+ self.position_displacement,
+ ]
+ )
+
+ def __tuple__(
+ self,
+ ) -> Union[
+ Tuple[bool, str, int, int, int, int, int, Tuple[float, float, float]],
+ Tuple[bool, str, int, int, int, int, Tuple[float, float, float]],
+ ]:
+ return (
+ (
+ self.percussive,
+ self.sound_name,
+ self.velocity,
+ self.start_tick,
+ self.duration,
+ self.track_no,
+ self.position_displacement,
+ )
+ if self.percussive
+ else (
+ self.percussive,
+ self.sound_name,
+ self.note_pitch,
+ self.velocity,
+ self.start_tick,
+ self.duration,
+ self.track_no,
+ self.position_displacement,
+ )
+ )
+
+ def __dict__(self):
+ return (
+ {
+ "Percussive": self.percussive,
+ "Instrument": self.sound_name,
+ "Velocity": self.velocity,
+ "StartTick": self.start_tick,
+ "Duration": self.duration,
+ "Track": self.track_no,
+ "PositionDisplacement": self.position_displacement,
+ }
+ if self.percussive
+ else {
+ "Percussive": self.percussive,
+ "Instrument": self.sound_name,
+ "Pitch": self.note_pitch,
+ "Velocity": self.velocity,
+ "StartTick": self.start_tick,
+ "Duration": self.duration,
+ "Track": self.track_no,
+ "PositionDisplacement": self.position_displacement,
+ }
+ )
+
+ def __eq__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return False
+ return self.tuplize() == other.tuplize()
+
+
@dataclass(init=False)
class SingleNote:
"""存储单个音符的类"""
@@ -59,8 +254,8 @@ class SingleNote:
velocity: int,
startime: int,
lastime: int,
+ is_percussion: bool,
track_number: int = 0,
- is_percussion: Optional[bool] = None,
extra_information: Any = None,
):
"""用于存储单个音符的类
@@ -82,12 +277,7 @@ class SingleNote:
"""音符持续时间 ms"""
self.track_no: int = track_number
"""音符所处的音轨"""
-
- self.percussive = (
- (is_percussion in MC_PERCUSSION_INSTRUMENT_LIST)
- if (is_percussion is None)
- else is_percussion
- )
+ self.percussive: bool = is_percussion
"""是否为打击乐器"""
self.extra_info = extra_information
@@ -176,7 +366,7 @@ class SingleNote:
@dataclass(init=False)
-class SingleCommand:
+class MineCommand:
"""存储单个指令的类"""
command_text: str
@@ -218,7 +408,7 @@ class SingleCommand:
self.annotation_text = annotation
def copy(self):
- return SingleCommand(
+ return MineCommand(
command=self.command_text,
condition=self.conditional,
tick_delay=self.delay,
@@ -399,3 +589,14 @@ NoteChannelType = Mapping[
Dict[int,Dict[int,List[SingleNote,],],]
"""
+
+
+MineNoteChannelType = Mapping[
+ int,
+ List[MineNote,],
+]
+"""
+我的世界频道信息类型
+
+Dict[int,Dict[int,List[MineNote,],],]
+"""
diff --git a/Musicreater/utils.py b/Musicreater/utils.py
index 7deacf3..053697c 100644
--- a/Musicreater/utils.py
+++ b/Musicreater/utils.py
@@ -18,8 +18,8 @@ Terms & Conditions: License.md in the root directory
import math
import random
-from .constants import MM_INSTRUMENT_RANGE_TABLE, MC_INSTRUMENT_BLOCKS_TABLE
-from .subclass import SingleNote
+from .constants import MC_INSTRUMENT_BLOCKS_TABLE, MM_INSTRUMENT_RANGE_TABLE
+from .subclass import SingleNote, MineNote
from .types import (
Any,
@@ -74,23 +74,25 @@ def inst_to_sould_with_deviation(
-------
tuple(str我的世界乐器名, int转换算法中的X)
"""
- return reference_table.get(
- instrumentID,
- default=default_instrument,
- ), 6
+ return (
+ reference_table.get(
+ instrumentID,
+ default_instrument,
+ ),
+ 6,
+ )
# 明明已经走了
# 凭什么还要在我心里留下缠绵缱绻
-def midi_inst_to_mc_sould(
+def midi_inst_to_mc_sound(
instrumentID: int,
reference_table: MidiInstrumentTableType,
default_instrument: str = "note.flute",
) -> str:
"""
- 返回midi的乐器ID对应的我的世界乐器名,对于音域转换算法,如下:
- 2**( ( msg.note - 66 ) / 12 ) 即为MC的音高
+ 返回midi的乐器ID对应的我的世界乐器名
Parameters
----------
@@ -101,17 +103,13 @@ def midi_inst_to_mc_sould(
Returns
-------
- tuple(str我的世界乐器名, int转换算法中的X)
+ str我的世界乐器名
"""
return reference_table.get(
instrumentID,
- default=default_instrument,
+ default_instrument,
)
- # 明明已经走了
- # 凭什么还要在我心里留下缠绵缱绻
-
-
def natural_curve(
vol: float,
@@ -157,44 +155,167 @@ def straight_line(vol: float) -> float:
return vol / -8 + 16
-def note_to_command_parameters(
- note_: SingleNote,
- reference_table: MidiInstrumentTableType,
- deviation: int = 0,
- volume_percentage: float = 1,
- volume_processing_method: Callable[[float], float] = natural_curve,
+def minenote_to_command_paramaters(
+ note_: MineNote,
+ pitch_deviation: float = 0,
) -> Tuple[
str,
- float,
+ Tuple[float, float, float],
float,
Union[float, Literal[None]],
]:
"""
- 将音符转为播放的指令
+ 将MineNote对象转为《我的世界》音符播放所需之参数
+ :param note_:MineNote 音符对象
+ :param deviation:float 音调偏移量
+
+ :return str[我的世界音符ID], Tuple[float,float,float]播放视角坐标, float[指令音量参数], float[指令音调参数]
+ """
+
+ return (
+ note_.sound_name,
+ note_.position_displacement,
+ note_.velocity / 127,
+ (
+ None
+ if note_.percussive
+ else 2 ** ((note_.note_pitch - 66 + pitch_deviation) / 12)
+ ),
+ )
+
+
+def single_note_to_command_parameters(
+ note_: SingleNote,
+ reference_table: MidiInstrumentTableType,
+ deviation: float = 0,
+ volume_processing_method: Callable[[float], float] = natural_curve,
+) -> Tuple[
+ str,
+ Tuple[float, float, float],
+ float,
+ Union[float, Literal[None]],
+]:
+ """
+ 将音符转为播放的指令之参数
:param note_:int 音符对象
:param reference_table:Dict[int, str] 转换对照表
- :param deviation:int 音调偏移量
- :param volume_percentage:int 音量占比(0,1]
+ :param deviation:float 音调偏移量
:param volume_proccessing_method:Callable[[float], float] 音量处理函数
- :return str[我的世界音符ID], float[播放距离], float[指令音量参数], float[指令音调参数]
+ :return str[我的世界音符ID], Tuple[float,float,float]播放视角坐标, float[指令音量参数], float[指令音调参数]
"""
- mc_sound_ID = midi_inst_to_mc_sould(
+
+ mc_sound_ID = midi_inst_to_mc_sound(
note_.inst,
reference_table,
"note.bd" if note_.percussive else "note.flute",
)
- # delaytime_now = round(self.start_time / float(speed) / 50)
- mc_pitch = None if note_.percussive else 2 ** ((note_.note - 66 + deviation) / 12)
+ mc_distance_volume = volume_processing_method(note_.velocity)
- mc_distance_volume = volume_processing_method(note_.velocity * volume_percentage)
-
- return mc_sound_ID, mc_distance_volume, volume_percentage, mc_pitch
+ return (
+ mc_sound_ID,
+ (0, mc_distance_volume, 0),
+ note_.velocity / 127,
+ None if note_.percussive else 2 ** ((note_.pitch - 66 + deviation) / 12),
+ )
-def from_single_note(
- note_: SingleNote, random_select: bool = False, default_block: str = "air"
+def midi_msgs_to_minenote(
+ inst_: int, # 乐器编号
+ note_: int,
+ percussive_: bool, # 是否作为打击乐器启用
+ velocity_: int,
+ start_time_: int,
+ duration_: int,
+ track_no_: int,
+ play_speed: float,
+ midi_reference_table: MidiInstrumentTableType,
+ volume_processing_method_: Callable[[float], float],
+) -> MineNote:
+ """
+ 将Midi信息转为我的世界音符对象
+ :param inst_: int 乐器编号
+ :param note_: int 音高编号(音符编号)
+ :param percussive_: bool 是否作为打击乐器启用
+ :param velocity_: int 力度(响度)
+ :param start_time_: int 音符起始时间(毫秒数)
+ :param duration_: int 音符持续时间(毫秒数)
+ :param track_no_: int 音符所处音轨
+ :param play_speed: float 曲目播放速度
+ :param midi_reference_table: Dict[int, str] 转换对照表
+ :param volume_proccessing_method_: Callable[[float], float] 音量处理函数
+
+ :return MineNote我的世界音符对象
+ """
+ mc_sound_ID = midi_inst_to_mc_sound(
+ inst_,
+ midi_reference_table,
+ "note.bd" if percussive_ else "note.flute",
+ )
+
+ mc_distance_volume = volume_processing_method_(velocity_)
+
+ return MineNote(
+ mc_sound_ID,
+ note_,
+ velocity_,
+ round(start_time_ / float(play_speed) / 50),
+ round(duration_ / float(play_speed) / 50),
+ track_no_,
+ percussive_,
+ (0, mc_distance_volume, 0),
+ )
+
+
+def single_note_to_minenote(
+ note_: SingleNote,
+ reference_table: MidiInstrumentTableType,
+ play_speed: float = 0,
+ volume_processing_method: Callable[[float], float] = natural_curve,
+) -> MineNote:
+ """
+ 将音符转为我的世界音符对象
+ :param note_:SingleNote 音符对象
+ :param reference_table:Dict[int, str] 转换对照表
+ :param play_speed:float 播放速度
+ :param volume_proccessing_method:Callable[[float], float] 音量处理函数
+
+ :return MineNote我的世界音符对象
+ """
+ mc_sound_ID = midi_inst_to_mc_sound(
+ note_.inst,
+ reference_table,
+ "note.bd" if note_.percussive else "note.flute",
+ )
+
+ mc_distance_volume = volume_processing_method(note_.velocity)
+
+ return MineNote(
+ mc_sound_ID,
+ note_.pitch,
+ note_.velocity,
+ round(note_.start_time / float(play_speed) / 50),
+ round(note_.duration / float(play_speed) / 50),
+ note_.track_no,
+ note_.percussive,
+ (0, mc_distance_volume, 0),
+ note_.extra_info,
+ )
+
+
+def is_in_diapason(note_pitch: int, instrument: str) -> bool:
+ note_range = MM_INSTRUMENT_RANGE_TABLE.get(instrument, ((-1, 128), 0))[0]
+ return note_pitch >= note_range[0] and note_pitch <= note_range[1]
+
+
+def is_note_in_diapason(note_: MineNote) -> bool:
+ note_range = MM_INSTRUMENT_RANGE_TABLE.get(note_.sound_name, ((-1, 128), 0))[0]
+ return note_.note_pitch >= note_range[0] and note_.note_pitch <= note_range[1]
+
+
+def note_to_redstone_block(
+ note_: MineNote, random_select: bool = False, default_block: str = "air"
):
"""
将我的世界乐器名改作音符盒所需的对应方块名称
diff --git a/README.md b/README.md
index 0d3b7da..5e3ff2d 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
-一款免费开源的《我的世界》数字音频库。
+一款免费开源的《我的世界》数字音频支持库。
@@ -33,7 +33,7 @@
## 介绍 🚀
-音·创 是一个免费开源的针对 **《我的世界》** 的 MIDI 音乐转换库
+音·创 是一款免费开源的针对 **《我的世界》** 音乐的支持库
欢迎加群:[861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
@@ -120,7 +120,7 @@ NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
-[Bilibili: 金羿ELS]: https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-00A1E7?style=for-the-badge
+[Bilibili: 金羿ELS]: https://img.shields.io/badge/Bilibili-%E9%87%91%E7%BE%BFELS-00A1E7?style=for-the-badge
[Bilibili: 诸葛亮与八卦阵]: https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-00A1E7?style=for-the-badge
[CodeStyle: black]: https://img.shields.io/badge/code%20style-black-121110.svg?style=for-the-badge
[python]: https://img.shields.io/badge/python-3.8-AB70FF?style=for-the-badge
diff --git a/README_EN.md b/README_EN.md
index 4538424..f620cf3 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -32,7 +32,7 @@
## Introduction🚀
-Musicreater is a free open-source library used for converting digital music files into formats that could be read in _Minecraft_.
+Musicreater is a free open-source library used for digital music that being played in _Minecraft_.
Welcome to join our QQ group: [861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
@@ -121,7 +121,7 @@ NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
- 上文提及的 网易 公司,指代的是在中国大陆运营《我的世界:中国版》的上海网之易网络科技发展有限公司
-[Bilibili: Eilles]: https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-00A1E7?style=for-the-badge
+[Bilibili: Eilles]: https://img.shields.io/badge/Bilibili-%E9%87%91%E7%BE%BFELS-00A1E7?style=for-the-badge
[Bilibili: bgArray]: https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-00A1E7?style=for-the-badge
[CodeStyle: black]: https://img.shields.io/badge/code%20style-black-121110.svg?style=for-the-badge
[python]: https://img.shields.io/badge/python-3.8-AB70FF?style=for-the-badge
diff --git a/RSMC_test.py b/RSMC_test.py
deleted file mode 100644
index 08c1ea4..0000000
--- a/RSMC_test.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import Musicreater.experiment
-
-
-print(
- Musicreater.experiment.FutureMidiConvertRSNB.from_midi_file(
- input("midi路径:"), old_exe_format=False
- ).to_note_list_in_delay()
-)
diff --git a/example.py b/example.py
index f3c3cfc..fbc9a22 100644
--- a/example.py
+++ b/example.py
@@ -80,11 +80,11 @@ else:
# 提示语 检测函数 错误提示语
for args in [
(
- f"输入音量:",
+ f"最小播放音量:",
float,
),
(
- f"输入播放速度:",
+ f"播放速度:",
float,
),
(
@@ -118,21 +118,19 @@ else:
if fileFormat == 1
else (
(
- (
- "结构延展方向:",
- lambda a: isin(
- a,
- {
- "z+": ["z+", "Z+"],
- "x+": ["X+", "x+"],
- "z-": ["Z-", "z-"],
- "x-": ["x-", "X-"],
- },
- ),
- )
- if (playerFormat == 2 and fileFormat == 2)
- else ()
- ),
+ "结构延展方向:",
+ lambda a: isin(
+ a,
+ {
+ "z+": ["z+", "Z+"],
+ "x+": ["X+", "x+"],
+ "z-": ["Z-", "z-"],
+ "x-": ["x-", "X-"],
+ },
+ ),
+ )
+ if (playerFormat == 2 and fileFormat == 2)
+ else ()
)
),
(
@@ -152,12 +150,17 @@ else:
),
]:
if args:
- prompts.append(args[1](input(args[0])))
+ try:
+ prompts.append(args[1](input(args[0])))
+ except Exception:
+ print(args)
print(f"正在处理 {midi_path} :")
-cvt_mid = Musicreater.MidiConvert.from_midi_file(midi_path, old_exe_format=False)
-cvt_cfg = ConvertConfig(out_path, *prompts[:3])
+cvt_mid = Musicreater.MidiConvert.from_midi_file(
+ midi_path, old_exe_format=False, min_volume=prompts[0], play_speed=prompts[1]
+)
+cvt_cfg = ConvertConfig(out_path, prompts[2])
if fileFormat == 0:
if playerFormat == 1:
diff --git a/example_futureFunction.py b/example_futureFunction.py
index 0daec0b..460eff0 100644
--- a/example_futureFunction.py
+++ b/example_futureFunction.py
@@ -7,7 +7,7 @@ print(
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
input("midi路径:"), old_exe_format=False
),
- Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
+ Musicreater.plugin.ConvertConfig(input("输出路径:"),),
max_height=32,
)
)
diff --git a/setup.py b/setup.py
index 3f05cb8..4f64130 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ setuptools.setup(
version=Musicreater.__version__,
author="Eilles Wan, bgArray",
author_email="TriM-Organization@hotmail.com",
- description="一款免费开源的 《我的世界》 mid音乐转换库。\n"
+ description="一款免费开源的针对《我的世界》音乐的支持库\n"
"A free open-source python library used to convert midi into Minecraft.",
long_description=long_description,
long_description_content_type="text/markdown",