mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2026-04-21 00:36:03 +00:00
完成 Midi 导入插件移植
This commit is contained in:
@@ -182,10 +182,10 @@ class FutureMidiConvertKamiRES(MidiConvert):
|
||||
raise ZeroSpeedError("播放速度为 0 ,其需要(0,1]范围内的实数。")
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
midi_channels: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
|
||||
channel_controler: Dict[int, Dict[str, int]] = empty_midi_channels(
|
||||
default_staff={
|
||||
channel_controler: Dict[int, Dict[str, int]] = enumerated_stuff_copy(
|
||||
staff={
|
||||
MIDI_PROGRAM: default_program_value,
|
||||
MIDI_VOLUME: default_volume_value,
|
||||
MIDI_PAN: 64,
|
||||
@@ -205,7 +205,7 @@ class FutureMidiConvertKamiRES(MidiConvert):
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(default_staff=[])
|
||||
] = enumerated_stuff_copy(staff=[])
|
||||
note_queue_B: Dict[
|
||||
int,
|
||||
List[
|
||||
@@ -214,7 +214,7 @@ class FutureMidiConvertKamiRES(MidiConvert):
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(default_staff=[])
|
||||
] = enumerated_stuff_copy(staff=[])
|
||||
|
||||
# 直接使用mido.midifiles.tracks.merge_tracks转为单轨
|
||||
# 采用的时遍历信息思路
|
||||
@@ -1042,7 +1042,7 @@ class FutureMidiConvertM5(MidiConvert):
|
||||
# )
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: ChannelType = empty_midi_channels()
|
||||
midi_channels: ChannelType = enumerated_stuff_copy()
|
||||
tempo = 500000
|
||||
|
||||
# 我们来用通道统计音乐信息
|
||||
@@ -1052,7 +1052,7 @@ class FutureMidiConvertM5(MidiConvert):
|
||||
if not track:
|
||||
continue
|
||||
|
||||
note_queue = empty_midi_channels(default_staff=[])
|
||||
note_queue = enumerated_stuff_copy(staff=[])
|
||||
|
||||
for msg in track:
|
||||
if msg.time != 0:
|
||||
|
||||
@@ -34,14 +34,6 @@ class MSCTBaseException(Exception):
|
||||
raise self
|
||||
|
||||
|
||||
class MidiFormatException(MSCTBaseException):
|
||||
"""音·创 的所有MIDI格式错误均继承于此"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""音·创 的所有MIDI格式错误均继承于此"""
|
||||
super().__init__("MIDI 格式错误", *args)
|
||||
|
||||
|
||||
class MidiDestroyedError(MSCTBaseException):
|
||||
"""Midi文件损坏"""
|
||||
|
||||
@@ -82,84 +74,3 @@ class CommandFormatError(MSCTBaseException, RuntimeError):
|
||||
# 那么这两个音符的音长无法判断。这是个好问题,但是不是我现在能解决的,也不是我们现在想解决的问题
|
||||
|
||||
|
||||
class NotDefineTempoError(MidiFormatException):
|
||||
"""没有Tempo设定导致时间无法计算的错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""没有Tempo设定导致时间无法计算的错误"""
|
||||
super().__init__("在曲目开始时没有声明 Tempo(未指定拍长)", *args)
|
||||
|
||||
|
||||
class ChannelOverFlowError(MidiFormatException):
|
||||
"""一个midi中含有过多的通道"""
|
||||
|
||||
def __init__(self, max_channel=16, *args):
|
||||
"""一个midi中含有过多的通道"""
|
||||
super().__init__("含有过多的通道(数量应≤{})".format(max_channel), *args)
|
||||
|
||||
|
||||
class NotDefineProgramError(MidiFormatException):
|
||||
"""没有Program设定导致没有乐器可以选择的错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""没有Program设定导致没有乐器可以选择的错误"""
|
||||
super().__init__("未指定演奏乐器", *args)
|
||||
|
||||
|
||||
class NoteOnOffMismatchError(MidiFormatException):
|
||||
"""音符开音和停止不匹配的错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""音符开音和停止不匹配的错误"""
|
||||
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__("播放速度为零", *args)
|
||||
|
||||
# 已重构
|
||||
class IllegalMinimumVolumeError(MSCTBaseException, ValueError):
|
||||
"""最小播放音量有误的错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""最小播放音量错误"""
|
||||
super().__init__("最小播放音量超出范围", *args)
|
||||
|
||||
|
||||
# 已重构
|
||||
class MusicSequenceDecodeError(MSCTBaseException):
|
||||
"""音乐序列解码错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""音乐序列无法正确解码的错误"""
|
||||
super().__init__("解码音符序列文件时出现问题", *args)
|
||||
|
||||
|
||||
# 已重构
|
||||
class MusicSequenceTypeError(MSCTBaseException):
|
||||
"""音乐序列类型错误"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""无法识别音符序列字节码的类型"""
|
||||
super().__init__("错误的音符序列字节类型", *args)
|
||||
|
||||
|
||||
# 已重构
|
||||
class MusicSequenceVerificationFailed(MusicSequenceDecodeError):
|
||||
"""音乐序列校验失败"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""音符序列文件与其校验值不一致"""
|
||||
super().__init__("音符序列文件校验失败", *args)
|
||||
|
||||
@@ -170,7 +170,7 @@ class MusicSequence:
|
||||
pitched_note_referance_table: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
|
||||
percussion_note_referance_table: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||
minimum_vol: float = 0.1,
|
||||
volume_processing_function: FittingFunctionType = velocity_2_distance_natural,
|
||||
volume_processing_function: FittingFunctionType = volume_2_distance_natural,
|
||||
panning_processing_function: FittingFunctionType = panning_2_rotation_linear,
|
||||
deviation: float = 0,
|
||||
note_referance_table_replacement: Dict[str, str] = {},
|
||||
@@ -273,7 +273,7 @@ class MusicSequence:
|
||||
8 : (stt_index := 8 + (group_1 >> 10))
|
||||
].decode("GB18030")
|
||||
|
||||
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
channels_: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
total_note_count = 0
|
||||
if verify:
|
||||
_header_index = stt_index
|
||||
@@ -415,7 +415,7 @@ class MusicSequence:
|
||||
_t6_buffer = _t2_buffer = 0
|
||||
|
||||
_channel_inst_chart: Dict[str, Dict[str, int]] = {}
|
||||
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
channels_: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
|
||||
for i in range(total_note_count):
|
||||
if verify:
|
||||
@@ -525,7 +525,7 @@ class MusicSequence:
|
||||
music_name_ = bytes_buffer_in[
|
||||
8 : (stt_index := 8 + (group_1 >> 10))
|
||||
].decode("GB18030")
|
||||
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
channels_: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
for channel_index in channels_.keys():
|
||||
for i in range(
|
||||
int.from_bytes(
|
||||
@@ -568,7 +568,7 @@ class MusicSequence:
|
||||
music_name_ = bytes_buffer_in[
|
||||
8 : (stt_index := 8 + (group_1 >> 10))
|
||||
].decode("utf-8")
|
||||
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
channels_: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
for channel_index in channels_.keys():
|
||||
for i in range(
|
||||
int.from_bytes(
|
||||
@@ -820,7 +820,7 @@ class MusicSequence:
|
||||
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,
|
||||
vol_processing_function: FittingFunctionType = velocity_2_distance_natural,
|
||||
vol_processing_function: FittingFunctionType = volume_2_distance_natural,
|
||||
pan_processing_function: FittingFunctionType = panning_2_rotation_trigonometric,
|
||||
note_rtable_replacement: Dict[str, str] = {},
|
||||
) -> Tuple[MineNoteChannelType, int, Dict[str, int]]:
|
||||
@@ -860,10 +860,10 @@ class MusicSequence:
|
||||
raise ZeroSpeedError("播放速度不得为零,应为 (0,1] 范围内的实数。")
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||
midi_channels: MineNoteChannelType = enumerated_stuff_copy(staff=[])
|
||||
|
||||
channel_controler: Dict[int, Dict[str, int]] = empty_midi_channels(
|
||||
default_staff={
|
||||
channel_controler: Dict[int, Dict[str, int]] = enumerated_stuff_copy(
|
||||
staff={
|
||||
MIDI_PROGRAM: default_program_value,
|
||||
MIDI_VOLUME: default_volume_value,
|
||||
MIDI_PAN: 64,
|
||||
@@ -883,7 +883,7 @@ class MusicSequence:
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(default_staff=[])
|
||||
] = enumerated_stuff_copy(staff=[])
|
||||
note_queue_B: Dict[
|
||||
int,
|
||||
List[
|
||||
@@ -892,7 +892,7 @@ class MusicSequence:
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(default_staff=[])
|
||||
] = enumerated_stuff_copy(staff=[])
|
||||
|
||||
lyric_cache: List[Tuple[int, str]] = []
|
||||
|
||||
@@ -1099,7 +1099,7 @@ class MidiConvert(MusicSequence):
|
||||
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||
enable_old_exe_format: bool = False,
|
||||
minimum_volume: float = 0.1,
|
||||
vol_processing_function: FittingFunctionType = velocity_2_distance_natural,
|
||||
vol_processing_function: FittingFunctionType = volume_2_distance_natural,
|
||||
pan_processing_function: FittingFunctionType = panning_2_rotation_trigonometric,
|
||||
pitch_deviation: float = 0,
|
||||
note_rtable_replacement: Dict[str, str] = {},
|
||||
@@ -1182,7 +1182,7 @@ class MidiConvert(MusicSequence):
|
||||
percussion_note_table: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||
old_exe_format: bool = False,
|
||||
min_volume: float = 0.1,
|
||||
vol_processing_func: FittingFunctionType = velocity_2_distance_natural,
|
||||
vol_processing_func: FittingFunctionType = volume_2_distance_natural,
|
||||
pan_processing_func: FittingFunctionType = panning_2_rotation_linear,
|
||||
music_pitch_deviation: float = 0,
|
||||
note_table_replacement: Dict[str, str] = {},
|
||||
|
||||
@@ -39,31 +39,15 @@ from Musicreater.constants import (
|
||||
MM_INSTRUMENT_DEVIATION_TABLE,
|
||||
MM_INSTRUMENT_RANGE_TABLE,
|
||||
)
|
||||
from .old_exceptions import MusicSequenceDecodeError
|
||||
from Musicreater.exceptions import SingleNoteDecodeError
|
||||
from Musicreater._utils import enumerated_stuffcopy_dictionary
|
||||
|
||||
from Musicreater.builtin_plugins.midi_read.utils import midi_inst_to_mc_sound
|
||||
|
||||
from .subclass import MineNote, mctick2timestr, SingleNoteBox
|
||||
from .old_types import MidiInstrumentTableType, MineNoteChannelType, FittingFunctionType
|
||||
|
||||
|
||||
def empty_midi_channels(
|
||||
channel_count: int = 17, default_staff: Any = {}
|
||||
) -> Dict[int, Any]:
|
||||
"""
|
||||
空MIDI通道字典
|
||||
"""
|
||||
|
||||
return dict(
|
||||
(
|
||||
i,
|
||||
(
|
||||
default_staff.copy()
|
||||
if isinstance(default_staff, (dict, list))
|
||||
else default_staff
|
||||
),
|
||||
) # 这告诉我们,你不能忽略任何一个复制的序列,因为它真的,我哭死,折磨我一整天,全在这个bug上了
|
||||
for i in range(channel_count)
|
||||
)
|
||||
|
||||
|
||||
def inst_to_sould_with_deviation(
|
||||
instrumentID: int,
|
||||
reference_table: MidiInstrumentTableType,
|
||||
@@ -99,34 +83,6 @@ def inst_to_sould_with_deviation(
|
||||
)
|
||||
|
||||
|
||||
def midi_inst_to_mc_sound(
|
||||
instrumentID: int,
|
||||
reference_table: MidiInstrumentTableType,
|
||||
default_instrument: str = "note.flute",
|
||||
) -> str:
|
||||
"""
|
||||
返回midi的乐器ID对应的我的世界乐器名
|
||||
|
||||
Parameters
|
||||
----------
|
||||
instrumentID: int
|
||||
midi的乐器ID
|
||||
reference_table: Dict[int, Tuple[str, int]]
|
||||
转换乐器参照表
|
||||
default_instrument: str
|
||||
查无此乐器时的替换乐器
|
||||
|
||||
Returns
|
||||
-------
|
||||
str我的世界乐器名
|
||||
"""
|
||||
return reference_table.get(
|
||||
instrumentID,
|
||||
default_instrument,
|
||||
)
|
||||
|
||||
|
||||
|
||||
def minenote_to_command_parameters(
|
||||
mine_note: MineNote,
|
||||
pitch_deviation: float = 0,
|
||||
@@ -175,85 +131,6 @@ def minenote_to_command_parameters(
|
||||
)
|
||||
|
||||
|
||||
def midi_msgs_to_minenote(
|
||||
inst_: int, # 乐器编号
|
||||
note_: int,
|
||||
percussive_: bool, # 是否作为打击乐器启用
|
||||
volume_: int,
|
||||
velocity_: int,
|
||||
panning_: int,
|
||||
start_time_: int,
|
||||
duration_: int,
|
||||
play_speed: float,
|
||||
midi_reference_table: MidiInstrumentTableType,
|
||||
volume_processing_method_: FittingFunctionType,
|
||||
panning_processing_method_: FittingFunctionType,
|
||||
note_table_replacement: Dict[str, str] = {},
|
||||
lyric_line: str = "",
|
||||
) -> MineNote:
|
||||
"""
|
||||
将Midi信息转为我的世界音符对象
|
||||
|
||||
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_,
|
||||
midi_reference_table,
|
||||
"note.bd" if percussive_ else "note.flute",
|
||||
)
|
||||
|
||||
return MineNote(
|
||||
mc_sound_name=note_table_replacement.get(mc_sound_ID, mc_sound_ID),
|
||||
midi_pitch=note_,
|
||||
midi_velocity=velocity_,
|
||||
start_time=(tk := int(start_time_ / float(play_speed) / 50000)),
|
||||
last_time=round(duration_ / float(play_speed) / 50000),
|
||||
mass_precision_time=round((start_time_ / float(play_speed) - tk * 50000) / 800),
|
||||
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_,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def midi_msgs_to_minenote_using_kami_respack(
|
||||
inst_: int, # 乐器编号
|
||||
note_: int,
|
||||
@@ -549,11 +426,10 @@ def load_decode_fsq_flush_release(
|
||||
)
|
||||
except Exception as _err:
|
||||
# print(bytes_buffer_in[stt_index:end_index])
|
||||
raise MusicSequenceDecodeError(
|
||||
_err,
|
||||
raise SingleNoteDecodeError(
|
||||
"所截取的音符码之首个字节:",
|
||||
_first_byte,
|
||||
)
|
||||
) from _err
|
||||
|
||||
|
||||
def load_decode_msq_flush_release(
|
||||
@@ -600,8 +476,8 @@ def load_decode_msq_flush_release(
|
||||
|
||||
_total_note_count = 1
|
||||
|
||||
_channel_infos = empty_midi_channels(
|
||||
default_staff={"NOW_INDEX": 0, "NOTE_COUNT": 0, "HAVE_READ": 0, "END_INDEX": -1}
|
||||
_channel_infos = enumerated_stuffcopy_dictionary(
|
||||
staff={"NOW_INDEX": 0, "NOTE_COUNT": 0, "HAVE_READ": 0, "END_INDEX": -1}
|
||||
)
|
||||
|
||||
for __channel_index in _channel_infos.keys():
|
||||
@@ -730,7 +606,7 @@ def load_decode_msq_flush_release(
|
||||
_total_note_count -= 1
|
||||
except Exception as _err:
|
||||
# print(channels_)
|
||||
raise MusicSequenceDecodeError("难以定位的解码错误", _err)
|
||||
raise SingleNoteDecodeError("难以定位的解码错误") from _err
|
||||
if not _read_in_note_list:
|
||||
break
|
||||
# _note_list.append
|
||||
Reference in New Issue
Block a user