mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2024-11-11 01:27:35 +08:00
高精度时间支持,修复tempo设置错误的问题
This commit is contained in:
parent
fe7c11636b
commit
bf1b7b99d8
@ -17,20 +17,20 @@ Terms & Conditions: License.md in the root directory
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
|
||||
__version__ = "2.1.0.1"
|
||||
__vername__ = "Websocket支持"
|
||||
__version__ = "2.2.0"
|
||||
__vername__ = "高精度时间支持"
|
||||
__author__ = (
|
||||
("金羿", "Eilles Wan"),
|
||||
("诸葛亮与八卦阵", "bgArray"),
|
||||
("偷吃不是Touch", "Touch"),
|
||||
("鱼旧梦", "ElapsingDreams"),
|
||||
("偷吃不是Touch", "Touch"),
|
||||
)
|
||||
__all__ = [
|
||||
# 主要类
|
||||
"MusicSequence",
|
||||
"MidiConvert",
|
||||
# 附加类
|
||||
"SingleNote",
|
||||
# "SingleNote",
|
||||
"MineNote",
|
||||
"MineCommand",
|
||||
"SingleNoteBox",
|
||||
|
@ -51,7 +51,7 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
_apply_time_division: float = 10,
|
||||
) -> List[MineNote]:
|
||||
"""传入音符数据,返回分割后的插值列表
|
||||
:param _note: SingleNote 音符
|
||||
:param _note: MineNote 音符
|
||||
:param _apply_time_division: int 间隔帧数
|
||||
:return list[tuple(int开始时间(毫秒), int乐器, int音符, int力度(内置), float音量(播放)),]"""
|
||||
|
||||
@ -81,7 +81,7 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
_note.start_tick + _i * (_note.duration / totalCount)
|
||||
),
|
||||
last_time=int(_note.duration / totalCount),
|
||||
track_number=_note.track_no,
|
||||
# track_number=_note.track_no,
|
||||
is_percussion=_note.percussive,
|
||||
extra_information=_note.extra_info,
|
||||
)
|
||||
@ -126,7 +126,7 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
)
|
||||
|
||||
if not note.percussive:
|
||||
notes_list.extend(self._linear_note(note,1 * note.extra_info[3]))
|
||||
notes_list.extend(self._linear_note(note, 1 * note.extra_info[3]))
|
||||
else:
|
||||
notes_list.append(note)
|
||||
|
||||
|
@ -38,7 +38,7 @@ from .utils import *
|
||||
|
||||
"""
|
||||
学习笔记:
|
||||
tempo: microseconds per quarter note 毫秒每四分音符,换句话说就是一拍占多少毫秒
|
||||
tempo: microseconds per quarter note 毫秒每四分音符,换句话说就是一拍占多少微秒
|
||||
tick: midi帧
|
||||
ticks_per_beat: 帧每拍,即一拍多少帧
|
||||
|
||||
@ -46,11 +46,11 @@ ticks_per_beat: 帧每拍,即一拍多少帧
|
||||
|
||||
tick / ticks_per_beat => amount_of_beats 拍数(四分音符数)
|
||||
|
||||
tempo * amount_of_beats => 毫秒数
|
||||
tempo * amount_of_beats => 微秒数
|
||||
|
||||
所以:
|
||||
|
||||
tempo * tick / ticks_per_beat => 毫秒数
|
||||
tempo * tick / ticks_per_beat => 微秒数
|
||||
|
||||
###########
|
||||
|
||||
@ -60,7 +60,7 @@ seconds per tick:
|
||||
seconds:
|
||||
tick * tempo / 1000000.0 / ticks_per_beat
|
||||
|
||||
microseconds:
|
||||
milliseconds:
|
||||
tick * tempo / 1000.0 / ticks_per_beat
|
||||
|
||||
gameticks:
|
||||
@ -225,8 +225,13 @@ class MusicSequence:
|
||||
"""从字节码导入音乐序列"""
|
||||
|
||||
group_1 = int.from_bytes(bytes_buffer_in[4:6], "big")
|
||||
group_2 = int.from_bytes(bytes_buffer_in[6:8], "big", signed=False)
|
||||
|
||||
high_quantity = bool(group_2 & 0b1000000000000000)
|
||||
# print(group_2, high_quantity)
|
||||
|
||||
music_name_ = bytes_buffer_in[8 : (stt_index := 8 + (group_1 >> 10))].decode(
|
||||
"utf-8"
|
||||
"GB18030"
|
||||
)
|
||||
channels_: MineNoteChannelType = empty_midi_channels(staff=[])
|
||||
for channel_index in channels_.keys():
|
||||
@ -236,9 +241,17 @@ class MusicSequence:
|
||||
)
|
||||
):
|
||||
try:
|
||||
end_index = stt_index + 14 + (bytes_buffer_in[stt_index] >> 2)
|
||||
end_index = (
|
||||
stt_index
|
||||
+ 13
|
||||
+ high_quantity
|
||||
+ (bytes_buffer_in[stt_index] >> 2)
|
||||
)
|
||||
channels_[channel_index].append(
|
||||
MineNote.decode(bytes_buffer_in[stt_index:end_index])
|
||||
MineNote.decode(
|
||||
code_buffer=bytes_buffer_in[stt_index:end_index],
|
||||
is_high_time_precision=high_quantity,
|
||||
)
|
||||
)
|
||||
stt_index = end_index
|
||||
except:
|
||||
@ -249,15 +262,21 @@ class MusicSequence:
|
||||
name_of_music=music_name_,
|
||||
channels_of_notes=channels_,
|
||||
minimum_volume_of_music=(group_1 & 0b1111111111) / 1000,
|
||||
deviation_value=int.from_bytes(bytes_buffer_in[6:8], "big", signed=True)
|
||||
/ 1000,
|
||||
deviation_value=(
|
||||
(-1 if group_2 & 0b100000000000000 else 1)
|
||||
* (group_2 & 0b11111111111111)
|
||||
/ 1000
|
||||
),
|
||||
)
|
||||
|
||||
def encode_dump(
|
||||
self,
|
||||
high_time_precision: bool = True,
|
||||
) -> bytes:
|
||||
"""将音乐序列转为二进制字节码"""
|
||||
|
||||
# 第一版的码头: MSQ# 字串编码: UTF-8
|
||||
# 第一版格式
|
||||
# 音乐名称长度 6 位 支持到 63
|
||||
# 最小音量 minimum_volume 10 位 最大支持 1023 即三位小数
|
||||
# 共 16 位 合 2 字节
|
||||
@ -266,20 +285,59 @@ class MusicSequence:
|
||||
# 共 16 位 合 2 字节
|
||||
# +++
|
||||
# 音乐名称 music_name 长度最多63 支持到 21 个中文字符 或 63 个西文字符
|
||||
|
||||
# bytes_buffer = (
|
||||
# b"MSQ#"
|
||||
# + (
|
||||
# (len(r := self.music_name.encode("utf-8")) << 10)
|
||||
# + round(self.minimum_volume * 1000)
|
||||
# ).to_bytes(2, "big")
|
||||
# + round(self.music_deviation * 1000).to_bytes(2, "big", signed=True)
|
||||
# + r
|
||||
# )
|
||||
|
||||
# for channel_index, note_list in self.channels.items():
|
||||
# bytes_buffer += len(note_list).to_bytes(4, "big")
|
||||
# for note_ in note_list:
|
||||
# bytes_buffer += note_.encode()
|
||||
|
||||
# 第二版的码头: MSQ@ 字串编码: GB18030
|
||||
|
||||
# 音乐名称长度 6 位 支持到 63
|
||||
# 最小音量 minimum_volume 10 位 最大支持 1023 即三位小数
|
||||
# 共 16 位 合 2 字节
|
||||
# +++
|
||||
# 是否启用“高精度”音符时间控制 1 位
|
||||
# 总音调偏移 music_deviation 15 位 最大支持 -16383 ~ 16383 即 三位小数
|
||||
# 共 16 位 合 2 字节
|
||||
# +++
|
||||
# 音乐名称 music_name 长度最多63 支持到 31 个中文字符 或 63 个西文字符
|
||||
|
||||
bytes_buffer = (
|
||||
b"MSQ#"
|
||||
b"MSQ@"
|
||||
+ (
|
||||
(len(r := self.music_name.encode("utf-8")) << 10)
|
||||
(len(r := self.music_name.encode("GB18030")) << 10)
|
||||
+ round(self.minimum_volume * 1000)
|
||||
).to_bytes(2, "big")
|
||||
+ round(self.music_deviation * 1000).to_bytes(2, "big", signed=True)
|
||||
+ (
|
||||
(
|
||||
(
|
||||
(high_time_precision << 1)
|
||||
+ (1 if (k := round(self.music_deviation * 1000)) < 0 else 0)
|
||||
)
|
||||
<< 14
|
||||
)
|
||||
+ abs(k)
|
||||
).to_bytes(2, "big", signed=False)
|
||||
+ r
|
||||
)
|
||||
|
||||
# 若启用“高精度”,则在每个音符前添加一个字节,用于存储音符时间控制精度偏移
|
||||
# 此值每增加 1,则音符向后播放时长增加 1/1250 秒
|
||||
for channel_index, note_list in self.channels.items():
|
||||
bytes_buffer += len(note_list).to_bytes(4, "big")
|
||||
for note_ in note_list:
|
||||
bytes_buffer += note_.encode()
|
||||
bytes_buffer += note_.encode(is_high_time_precision=high_time_precision)
|
||||
|
||||
return bytes_buffer
|
||||
|
||||
@ -374,8 +432,6 @@ class MusicSequence:
|
||||
----------
|
||||
midi: mido.MidiFile 对象
|
||||
需要处理的midi对象
|
||||
ignore_mismatch_error: bool
|
||||
是否在导入时忽略音符不匹配错误
|
||||
speed: float
|
||||
音乐播放速度倍数
|
||||
default_tempo_value: int
|
||||
@ -398,115 +454,110 @@ class MusicSequence:
|
||||
|
||||
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
|
||||
midi_channels: MineNoteChannelType = empty_midi_channels(staff=[])
|
||||
channel_program: Dict[int, int] = empty_midi_channels(staff=-1)
|
||||
tempo = default_tempo_value
|
||||
note_count = 0
|
||||
note_count_per_instrument: Dict[str, int] = {}
|
||||
microseconds = 0
|
||||
|
||||
# 我们来用通道统计音乐信息
|
||||
# 但是是用分轨的思路的
|
||||
for track_no, track in enumerate(midi.tracks):
|
||||
microseconds = 0
|
||||
if not track:
|
||||
continue
|
||||
note_queue_A: Dict[
|
||||
int,
|
||||
List[
|
||||
Tuple[
|
||||
int,
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(staff=[])
|
||||
note_queue_B: Dict[
|
||||
int,
|
||||
List[
|
||||
Tuple[
|
||||
int,
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(staff=[])
|
||||
|
||||
note_queue_A: Dict[
|
||||
int,
|
||||
List[
|
||||
Tuple[
|
||||
int,
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(staff=[])
|
||||
note_queue_B: Dict[
|
||||
int,
|
||||
List[
|
||||
Tuple[
|
||||
int,
|
||||
int,
|
||||
]
|
||||
],
|
||||
] = empty_midi_channels(staff=[])
|
||||
# 直接使用mido.midifiles.tracks.merge_tracks转为单轨
|
||||
# 采用的时遍历信息思路
|
||||
for msg in midi.merged_track:
|
||||
if msg.time != 0:
|
||||
# 微秒
|
||||
microseconds += msg.time * tempo / midi.ticks_per_beat
|
||||
|
||||
channel_program: Dict[int, int] = empty_midi_channels(staff=-1)
|
||||
# 简化
|
||||
if msg.type == "set_tempo":
|
||||
tempo = msg.tempo
|
||||
else:
|
||||
if msg.type == "program_change":
|
||||
channel_program[msg.channel] = msg.program
|
||||
|
||||
for msg in track:
|
||||
if msg.time != 0:
|
||||
microseconds += msg.time * tempo / midi.ticks_per_beat / 1000
|
||||
elif msg.type == "note_on" and msg.velocity != 0:
|
||||
note_queue_A[msg.channel].append(
|
||||
(msg.note, channel_program[msg.channel])
|
||||
)
|
||||
note_queue_B[msg.channel].append((msg.velocity, microseconds))
|
||||
|
||||
if msg.is_meta:
|
||||
if msg.type == "set_tempo":
|
||||
tempo = msg.tempo
|
||||
else:
|
||||
if msg.type == "program_change":
|
||||
channel_program[msg.channel] = msg.program
|
||||
|
||||
elif msg.type == "note_on" and msg.velocity != 0:
|
||||
note_queue_A[msg.channel].append(
|
||||
(msg.note, channel_program[msg.channel])
|
||||
)
|
||||
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_program[msg.channel]) in note_queue_A[
|
||||
msg.channel
|
||||
]:
|
||||
_velocity, _ms = note_queue_B[msg.channel][
|
||||
note_queue_A[msg.channel].index(
|
||||
(msg.note, channel_program[msg.channel])
|
||||
)
|
||||
]
|
||||
note_queue_A[msg.channel].remove(
|
||||
elif (msg.type == "note_off") or (
|
||||
msg.type == "note_on" and msg.velocity == 0
|
||||
):
|
||||
if (msg.note, channel_program[msg.channel]) in note_queue_A[
|
||||
msg.channel
|
||||
]:
|
||||
_velocity, _ms = note_queue_B[msg.channel][
|
||||
note_queue_A[msg.channel].index(
|
||||
(msg.note, channel_program[msg.channel])
|
||||
)
|
||||
note_queue_B[msg.channel].remove((_velocity, _ms))
|
||||
]
|
||||
note_queue_A[msg.channel].remove(
|
||||
(msg.note, channel_program[msg.channel])
|
||||
)
|
||||
note_queue_B[msg.channel].remove((_velocity, _ms))
|
||||
|
||||
midi_channels[msg.channel].append(
|
||||
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,
|
||||
midi_channels[msg.channel].append(
|
||||
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, # 微秒
|
||||
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_instrument.keys():
|
||||
note_count_per_instrument[that_note.sound_name] += 1
|
||||
else:
|
||||
note_count_per_instrument[that_note.sound_name] = 1
|
||||
else:
|
||||
if ignore_mismatch_error:
|
||||
print(
|
||||
"[WARRING] MIDI格式错误 音符不匹配 {} 无法在上文中找到与之匹配的音符开音消息".format(
|
||||
msg
|
||||
)
|
||||
)
|
||||
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:
|
||||
if ignore_mismatch_error:
|
||||
print(
|
||||
"[WARRING] MIDI格式错误 音符不匹配 {} 无法在上文中找到与之匹配的音符开音消息".format(
|
||||
msg
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise NoteOnOffMismatchError(
|
||||
"当前的MIDI很可能有损坏之嫌……",
|
||||
msg,
|
||||
"无法在上文中找到与之匹配的音符开音消息。",
|
||||
)
|
||||
raise NoteOnOffMismatchError(
|
||||
"当前的MIDI很可能有损坏之嫌……",
|
||||
msg,
|
||||
"无法在上文中找到与之匹配的音符开音消息。",
|
||||
)
|
||||
|
||||
"""整合后的音乐通道格式
|
||||
每个通道包括若干消息元素其中逃不过这三种:
|
||||
|
@ -272,3 +272,27 @@ def to_mcstructure_files_in_repeater_divided_by_instruments(
|
||||
struct.dump(f)
|
||||
|
||||
return max_delay
|
||||
|
||||
|
||||
def to_mcstructure_file_in_blocks(
|
||||
midi_cvt: MidiConvert,
|
||||
dist_path: str,
|
||||
player: str = "@a",
|
||||
):
|
||||
"""
|
||||
将midi以方块形式转换为mcstructure结构文件
|
||||
|
||||
Parameters
|
||||
----------
|
||||
midi_cvt: MidiConvert 对象
|
||||
用于转换的MidiConvert对象
|
||||
dist_path: str
|
||||
转换结果输出的目标路径
|
||||
player: str
|
||||
玩家选择器,默认为`@a`
|
||||
|
||||
Returns
|
||||
-------
|
||||
int音乐总延迟
|
||||
"""
|
||||
pass
|
||||
|
@ -42,8 +42,8 @@ class MineNote:
|
||||
duration: int
|
||||
"""音符持续时间 命令刻"""
|
||||
|
||||
track_no: int
|
||||
"""音符所处的音轨"""
|
||||
high_precision_time: int
|
||||
"""高精度开始时间偏量 1/1250 秒"""
|
||||
|
||||
percussive: bool
|
||||
"""是否作为打击乐器启用"""
|
||||
@ -61,7 +61,7 @@ class MineNote:
|
||||
midi_velocity: int,
|
||||
start_time: int,
|
||||
last_time: int,
|
||||
track_number: int = 0,
|
||||
mass_precision_time: int = 0,
|
||||
is_percussion: Optional[bool] = None,
|
||||
displacement: Optional[Tuple[float, float, float]] = None,
|
||||
extra_information: Optional[Any] = None,
|
||||
@ -73,7 +73,7 @@ class MineNote:
|
||||
:param start_time:`int` 开始之时(命令刻)
|
||||
注:此处的时间是用从乐曲开始到当前的毫秒数
|
||||
:param last_time:`int` 音符延续时间(命令刻)
|
||||
:param track_number:`int` 音轨编号
|
||||
:param mass_precision_time:`int` 高精度的开始时间偏移量(1/1250秒)
|
||||
:param is_percussion:`bool` 是否作为打击乐器
|
||||
:param displacement:`tuple[int,int,int]` 声像位移
|
||||
:param extra_information:`Any` 附加信息"""
|
||||
@ -87,8 +87,8 @@ class MineNote:
|
||||
"""开始之时 tick"""
|
||||
self.duration: int = last_time
|
||||
"""音符持续时间 tick"""
|
||||
self.track_no: int = track_number
|
||||
"""音符所处的音轨"""
|
||||
self.high_precision_time: int = mass_precision_time
|
||||
"""高精度开始时间偏量 0.4 毫秒"""
|
||||
|
||||
self.percussive = (
|
||||
(mc_sound_name in MC_PERCUSSION_INSTRUMENT_LIST)
|
||||
@ -105,7 +105,7 @@ class MineNote:
|
||||
self.extra_info = extra_information
|
||||
|
||||
@classmethod
|
||||
def decode(cls, code_buffer: bytes):
|
||||
def decode(cls, code_buffer: bytes, is_high_time_precision: bool = True):
|
||||
"""自字节码析出MineNote类"""
|
||||
group_1 = int.from_bytes(code_buffer[:6], "big")
|
||||
percussive_ = bool(group_1 & 0b1)
|
||||
@ -117,17 +117,31 @@ class MineNote:
|
||||
if code_buffer[6] & 0b1:
|
||||
position_displacement_ = (
|
||||
int.from_bytes(
|
||||
code_buffer[8 + sound_name_length : 10 + sound_name_length],
|
||||
(
|
||||
code_buffer[8 + sound_name_length : 10 + sound_name_length]
|
||||
if is_high_time_precision
|
||||
else code_buffer[7 + sound_name_length : 9 + sound_name_length]
|
||||
),
|
||||
"big",
|
||||
)
|
||||
/ 1000,
|
||||
int.from_bytes(
|
||||
code_buffer[10 + sound_name_length : 12 + sound_name_length],
|
||||
(
|
||||
code_buffer[10 + sound_name_length : 12 + sound_name_length]
|
||||
if is_high_time_precision
|
||||
else code_buffer[9 + sound_name_length : 11 + sound_name_length]
|
||||
),
|
||||
"big",
|
||||
)
|
||||
/ 1000,
|
||||
int.from_bytes(
|
||||
code_buffer[12 + sound_name_length : 14 + sound_name_length],
|
||||
(
|
||||
code_buffer[12 + sound_name_length : 14 + sound_name_length]
|
||||
if is_high_time_precision
|
||||
else code_buffer[
|
||||
11 + sound_name_length : 13 + sound_name_length
|
||||
]
|
||||
),
|
||||
"big",
|
||||
)
|
||||
/ 1000,
|
||||
@ -137,22 +151,28 @@ class MineNote:
|
||||
|
||||
try:
|
||||
return cls(
|
||||
mc_sound_name=code_buffer[8 : 8 + sound_name_length].decode(
|
||||
encoding="utf-8"
|
||||
),
|
||||
mc_sound_name=(
|
||||
o := (
|
||||
code_buffer[8 : 8 + sound_name_length]
|
||||
if is_high_time_precision
|
||||
else code_buffer[7 : 7 + sound_name_length]
|
||||
)
|
||||
).decode(encoding="GB18030"),
|
||||
midi_pitch=note_pitch_,
|
||||
midi_velocity=code_buffer[6] >> 1,
|
||||
start_time=start_tick_,
|
||||
last_time=duration_,
|
||||
track_number=code_buffer[7],
|
||||
mass_precision_time=code_buffer[7] if is_high_time_precision else 0,
|
||||
is_percussion=percussive_,
|
||||
displacement=position_displacement_,
|
||||
)
|
||||
except:
|
||||
print(code_buffer, "\n", code_buffer[8 : 8 + sound_name_length])
|
||||
print(code_buffer, "\n", o)
|
||||
raise
|
||||
|
||||
def encode(self, is_displacement_included: bool = True) -> bytes:
|
||||
def encode(
|
||||
self, is_displacement_included: bool = True, is_high_time_precision: bool = True
|
||||
) -> bytes:
|
||||
"""
|
||||
将数据打包为字节码
|
||||
|
||||
@ -172,9 +192,14 @@ class MineNote:
|
||||
# is_displacement_included 长度 1 位 支持到 1
|
||||
# 共 8 位 合 1 字节
|
||||
# +++
|
||||
# (在第二版中已舍弃)
|
||||
# track_no 长度 8 位 支持到 255 合 1 字节
|
||||
# (在第二版中新增)
|
||||
# high_time_precision(可选)长度 8 位 支持到 255 合 1 字节 支持 1/1250 秒
|
||||
# +++
|
||||
# sound_name 长度最多63 支持到 21 个中文字符 或 63 个西文字符
|
||||
# sound_name 长度最多 63 支持到 31 个中文字符 或 63 个西文字符
|
||||
# 第一版编码: UTF-8
|
||||
# 第二版编码: GB18030
|
||||
# +++
|
||||
# position_displacement 每个元素长 16 位 合 2 字节
|
||||
# 共 48 位 合 6 字节 支持存储三位小数和两位整数,其值必须在 [0, 65.535] 之间
|
||||
@ -190,7 +215,7 @@ class MineNote:
|
||||
(
|
||||
len(
|
||||
r := self.sound_name.encode(
|
||||
encoding="utf-8"
|
||||
encoding="GB18030"
|
||||
)
|
||||
)
|
||||
<< 7
|
||||
@ -210,7 +235,12 @@ class MineNote:
|
||||
+ self.percussive
|
||||
).to_bytes(6, "big")
|
||||
+ ((self.velocity << 1) + is_displacement_included).to_bytes(1, "big")
|
||||
+ self.track_no.to_bytes(1, "big")
|
||||
# + self.track_no.to_bytes(1, "big")
|
||||
+ (
|
||||
self.high_precision_time.to_bytes(1, "big")
|
||||
if is_high_time_precision
|
||||
else b""
|
||||
)
|
||||
+ r
|
||||
+ (
|
||||
(
|
||||
@ -227,7 +257,7 @@ class MineNote:
|
||||
"""设置附加信息"""
|
||||
self.extra_info = sth
|
||||
|
||||
def __str__(self, is_displacement: bool = False, is_track: bool = False):
|
||||
def __str__(self, is_displacement: bool = False):
|
||||
return "{}Note(Instrument = {}, {}Velocity = {}, StartTick = {}, Duration = {}{}{})".format(
|
||||
"Percussive" if self.percussive else "",
|
||||
self.sound_name,
|
||||
@ -235,7 +265,6 @@ class MineNote:
|
||||
self.velocity,
|
||||
self.start_tick,
|
||||
self.duration,
|
||||
", Track = {}".format(self.track_no) if is_track else "",
|
||||
(
|
||||
", PositionDisplacement = {}".format(self.position_displacement)
|
||||
if is_displacement
|
||||
@ -243,13 +272,9 @@ class MineNote:
|
||||
),
|
||||
)
|
||||
|
||||
def tuplize(self, is_displacement: bool = False, is_track: bool = False):
|
||||
def tuplize(self, is_displacement: bool = False):
|
||||
tuplized = self.__tuple__()
|
||||
return (
|
||||
tuplized[:-2]
|
||||
+ ((tuplized[-2],) if is_track else ())
|
||||
+ ((tuplized[-1],) if is_displacement else ())
|
||||
)
|
||||
return tuplized[:-2] + ((tuplized[-1],) if is_displacement else ())
|
||||
|
||||
def __list__(self) -> List:
|
||||
return (
|
||||
@ -259,7 +284,6 @@ class MineNote:
|
||||
self.velocity,
|
||||
self.start_tick,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
self.position_displacement,
|
||||
]
|
||||
if self.percussive
|
||||
@ -270,7 +294,6 @@ class MineNote:
|
||||
self.velocity,
|
||||
self.start_tick,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
self.position_displacement,
|
||||
]
|
||||
)
|
||||
@ -278,8 +301,8 @@ class MineNote:
|
||||
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]],
|
||||
Tuple[bool, str, int, int, int, Tuple[float, float, float]],
|
||||
]:
|
||||
return (
|
||||
(
|
||||
@ -288,7 +311,6 @@ class MineNote:
|
||||
self.velocity,
|
||||
self.start_tick,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
self.position_displacement,
|
||||
)
|
||||
if self.percussive
|
||||
@ -299,7 +321,6 @@ class MineNote:
|
||||
self.velocity,
|
||||
self.start_tick,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
self.position_displacement,
|
||||
)
|
||||
)
|
||||
@ -312,7 +333,6 @@ class MineNote:
|
||||
"Velocity": self.velocity,
|
||||
"StartTick": self.start_tick,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
"PositionDisplacement": self.position_displacement,
|
||||
}
|
||||
if self.percussive
|
||||
@ -323,7 +343,6 @@ class MineNote:
|
||||
"Velocity": self.velocity,
|
||||
"StartTick": self.start_tick,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
"PositionDisplacement": self.position_displacement,
|
||||
}
|
||||
)
|
||||
@ -334,150 +353,150 @@ class MineNote:
|
||||
return self.tuplize() == other.tuplize()
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class SingleNote:
|
||||
"""存储单个音符的类"""
|
||||
# @dataclass(init=False)
|
||||
# class SingleNote:
|
||||
# """存储单个音符的类"""
|
||||
|
||||
instrument: int
|
||||
"""乐器编号"""
|
||||
# instrument: int
|
||||
# """乐器编号"""
|
||||
|
||||
note: int
|
||||
"""音符编号"""
|
||||
# note: int
|
||||
# """音符编号"""
|
||||
|
||||
velocity: int
|
||||
"""力度/响度"""
|
||||
# velocity: int
|
||||
# """力度/响度"""
|
||||
|
||||
start_time: int
|
||||
"""开始之时 ms"""
|
||||
# start_time: int
|
||||
# """开始之时 ms"""
|
||||
|
||||
duration: int
|
||||
"""音符持续时间 ms"""
|
||||
# duration: int
|
||||
# """音符持续时间 ms"""
|
||||
|
||||
track_no: int
|
||||
"""音符所处的音轨"""
|
||||
# track_no: int
|
||||
# """音符所处的音轨"""
|
||||
|
||||
percussive: bool
|
||||
"""是否为打击乐器"""
|
||||
# percussive: bool
|
||||
# """是否为打击乐器"""
|
||||
|
||||
extra_info: Any
|
||||
"""你觉得放什么好?"""
|
||||
# extra_info: Any
|
||||
# """你觉得放什么好?"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
instrument: int,
|
||||
pitch: int,
|
||||
velocity: int,
|
||||
startime: int,
|
||||
lastime: int,
|
||||
is_percussion: bool,
|
||||
track_number: int = 0,
|
||||
extra_information: Any = None,
|
||||
):
|
||||
"""用于存储单个音符的类
|
||||
:param instrument 乐器编号
|
||||
:param pitch 音符编号
|
||||
:param velocity 力度/响度
|
||||
:param startTime 开始之时(ms)
|
||||
注:此处的时间是用从乐曲开始到当前的毫秒数
|
||||
:param lastTime 音符延续时间(ms)"""
|
||||
self.instrument: int = instrument
|
||||
"""乐器编号"""
|
||||
self.note: int = pitch
|
||||
"""音符编号"""
|
||||
self.velocity: int = velocity
|
||||
"""力度/响度"""
|
||||
self.start_time: int = startime
|
||||
"""开始之时 ms"""
|
||||
self.duration: int = lastime
|
||||
"""音符持续时间 ms"""
|
||||
self.track_no: int = track_number
|
||||
"""音符所处的音轨"""
|
||||
self.percussive: bool = is_percussion
|
||||
"""是否为打击乐器"""
|
||||
# def __init__(
|
||||
# self,
|
||||
# instrument: int,
|
||||
# pitch: int,
|
||||
# velocity: int,
|
||||
# startime: int,
|
||||
# lastime: int,
|
||||
# is_percussion: bool,
|
||||
# track_number: int = 0,
|
||||
# extra_information: Any = None,
|
||||
# ):
|
||||
# """用于存储单个音符的类
|
||||
# :param instrument 乐器编号
|
||||
# :param pitch 音符编号
|
||||
# :param velocity 力度/响度
|
||||
# :param startTime 开始之时(ms)
|
||||
# 注:此处的时间是用从乐曲开始到当前的毫秒数
|
||||
# :param lastTime 音符延续时间(ms)"""
|
||||
# self.instrument: int = instrument
|
||||
# """乐器编号"""
|
||||
# self.note: int = pitch
|
||||
# """音符编号"""
|
||||
# self.velocity: int = velocity
|
||||
# """力度/响度"""
|
||||
# self.start_time: int = startime
|
||||
# """开始之时 ms"""
|
||||
# self.duration: int = lastime
|
||||
# """音符持续时间 ms"""
|
||||
# self.track_no: int = track_number
|
||||
# """音符所处的音轨"""
|
||||
# self.percussive: bool = is_percussion
|
||||
# """是否为打击乐器"""
|
||||
|
||||
self.extra_info = extra_information
|
||||
# self.extra_info = extra_information
|
||||
|
||||
@property
|
||||
def inst(self) -> int:
|
||||
"""乐器编号"""
|
||||
return self.instrument
|
||||
# @property
|
||||
# def inst(self) -> int:
|
||||
# """乐器编号"""
|
||||
# return self.instrument
|
||||
|
||||
@inst.setter
|
||||
def inst(self, inst_: int):
|
||||
self.instrument = inst_
|
||||
# @inst.setter
|
||||
# def inst(self, inst_: int):
|
||||
# self.instrument = inst_
|
||||
|
||||
@property
|
||||
def pitch(self) -> int:
|
||||
"""音符编号"""
|
||||
return self.note
|
||||
# @property
|
||||
# def pitch(self) -> int:
|
||||
# """音符编号"""
|
||||
# return self.note
|
||||
|
||||
# @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)
|
||||
# # @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 set_info(self, sth: Any):
|
||||
# """设置附加信息"""
|
||||
# self.extra_info = sth
|
||||
|
||||
def __str__(self, is_track: bool = False):
|
||||
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format(
|
||||
"Percussive" if self.percussive else "",
|
||||
self.inst,
|
||||
"" if self.percussive else "Pitch = {}, ".format(self.pitch),
|
||||
self.start_time,
|
||||
self.duration,
|
||||
", Track = {}".format(self.track_no) if is_track else "",
|
||||
)
|
||||
# def __str__(self, is_track: bool = False):
|
||||
# return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format(
|
||||
# "Percussive" if self.percussive else "",
|
||||
# self.inst,
|
||||
# "" if self.percussive else "Pitch = {}, ".format(self.pitch),
|
||||
# self.start_time,
|
||||
# self.duration,
|
||||
# ", Track = {}".format(self.track_no) if is_track else "",
|
||||
# )
|
||||
|
||||
def __tuple__(self):
|
||||
return (
|
||||
(
|
||||
self.percussive,
|
||||
self.inst,
|
||||
self.velocity,
|
||||
self.start_time,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
)
|
||||
if self.percussive
|
||||
else (
|
||||
self.percussive,
|
||||
self.inst,
|
||||
self.note,
|
||||
self.velocity,
|
||||
self.start_time,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
)
|
||||
)
|
||||
# def __tuple__(self):
|
||||
# return (
|
||||
# (
|
||||
# self.percussive,
|
||||
# self.inst,
|
||||
# self.velocity,
|
||||
# self.start_time,
|
||||
# self.duration,
|
||||
# self.track_no,
|
||||
# )
|
||||
# if self.percussive
|
||||
# else (
|
||||
# self.percussive,
|
||||
# self.inst,
|
||||
# self.note,
|
||||
# self.velocity,
|
||||
# self.start_time,
|
||||
# self.duration,
|
||||
# self.track_no,
|
||||
# )
|
||||
# )
|
||||
|
||||
def __dict__(self):
|
||||
return (
|
||||
{
|
||||
"Percussive": self.percussive,
|
||||
"Instrument": self.inst,
|
||||
"Velocity": self.velocity,
|
||||
"StartTime": self.start_time,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
}
|
||||
if self.percussive
|
||||
else {
|
||||
"Percussive": self.percussive,
|
||||
"Instrument": self.inst,
|
||||
"Pitch": self.note,
|
||||
"Velocity": self.velocity,
|
||||
"StartTime": self.start_time,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
}
|
||||
)
|
||||
# def __dict__(self):
|
||||
# return (
|
||||
# {
|
||||
# "Percussive": self.percussive,
|
||||
# "Instrument": self.inst,
|
||||
# "Velocity": self.velocity,
|
||||
# "StartTime": self.start_time,
|
||||
# "Duration": self.duration,
|
||||
# "Track": self.track_no,
|
||||
# }
|
||||
# if self.percussive
|
||||
# else {
|
||||
# "Percussive": self.percussive,
|
||||
# "Instrument": self.inst,
|
||||
# "Pitch": self.note,
|
||||
# "Velocity": self.velocity,
|
||||
# "StartTime": self.start_time,
|
||||
# "Duration": self.duration,
|
||||
# "Track": self.track_no,
|
||||
# }
|
||||
# )
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, self.__class__):
|
||||
return False
|
||||
return self.__str__() == other.__str__()
|
||||
# def __eq__(self, other) -> bool:
|
||||
# if not isinstance(other, self.__class__):
|
||||
# return False
|
||||
# return self.__str__() == other.__str__()
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
@ -736,7 +755,10 @@ class ProgressBarStyle:
|
||||
.replace(r"%^s", str(total_delays))
|
||||
.replace(r"%%t", mctick2timestr(played_delays))
|
||||
.replace(r"%^t", mctick2timestr(total_delays))
|
||||
.replace(r"%%%", "{:0>5.2f}%".format(int(10000 * played_delays / total_delays) / 100))
|
||||
.replace(
|
||||
r"%%%",
|
||||
"{:0>5.2f}%".format(int(10000 * played_delays / total_delays) / 100),
|
||||
)
|
||||
.replace(
|
||||
"_",
|
||||
self.played_style,
|
||||
@ -762,15 +784,15 @@ DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle(
|
||||
默认的进度条样式
|
||||
"""
|
||||
|
||||
NoteChannelType = Mapping[
|
||||
int,
|
||||
List[SingleNote,],
|
||||
]
|
||||
"""
|
||||
频道信息类型
|
||||
# NoteChannelType = Mapping[
|
||||
# int,
|
||||
# List[SingleNote,],
|
||||
# ]
|
||||
# """
|
||||
# 频道信息类型
|
||||
|
||||
Dict[int,Dict[int,List[SingleNote,],],]
|
||||
"""
|
||||
# Dict[int,Dict[int,List[SingleNote,],],]
|
||||
# """
|
||||
|
||||
|
||||
MineNoteChannelType = Mapping[
|
||||
|
@ -24,7 +24,7 @@ from .constants import (
|
||||
MC_PITCHED_INSTRUMENT_LIST,
|
||||
MM_INSTRUMENT_RANGE_TABLE,
|
||||
)
|
||||
from .subclass import SingleNote, MineNote, mctick2timestr
|
||||
from .subclass import MineNote, mctick2timestr
|
||||
|
||||
from .types import (
|
||||
Any,
|
||||
@ -38,7 +38,6 @@ from .types import (
|
||||
)
|
||||
|
||||
|
||||
|
||||
def empty_midi_channels(channel_count: int = 17, staff: Any = {}) -> Dict[int, Any]:
|
||||
"""
|
||||
空MIDI通道字典
|
||||
@ -199,41 +198,41 @@ def minenote_to_command_paramaters(
|
||||
)
|
||||
|
||||
|
||||
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:float 音调偏移量
|
||||
:param volume_proccessing_method:Callable[[float], float] 音量处理函数
|
||||
# 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:float 音调偏移量
|
||||
# :param volume_proccessing_method:Callable[[float], float] 音量处理函数
|
||||
|
||||
:return str[我的世界音符ID], Tuple[float,float,float]播放视角坐标, float[指令音量参数], float[指令音调参数]
|
||||
"""
|
||||
# :return str[我的世界音符ID], Tuple[float,float,float]播放视角坐标, float[指令音量参数], float[指令音调参数]
|
||||
# """
|
||||
|
||||
mc_sound_ID, _X = inst_to_sould_with_deviation(
|
||||
note_.inst,
|
||||
reference_table,
|
||||
"note.bd" if note_.percussive else "note.flute",
|
||||
)
|
||||
# mc_sound_ID, _X = inst_to_sould_with_deviation(
|
||||
# note_.inst,
|
||||
# reference_table,
|
||||
# "note.bd" if note_.percussive else "note.flute",
|
||||
# )
|
||||
|
||||
mc_distance_volume = volume_processing_method(note_.velocity)
|
||||
# mc_distance_volume = volume_processing_method(note_.velocity)
|
||||
|
||||
return (
|
||||
mc_sound_ID,
|
||||
(0, mc_distance_volume, 0),
|
||||
note_.velocity / 127,
|
||||
None if note_.percussive else 2 ** ((note_.pitch - 60 - _X + deviation) / 12),
|
||||
)
|
||||
# return (
|
||||
# mc_sound_ID,
|
||||
# (0, mc_distance_volume, 0),
|
||||
# note_.velocity / 127,
|
||||
# None if note_.percussive else 2 ** ((note_.pitch - 60 - _X + deviation) / 12),
|
||||
# )
|
||||
|
||||
|
||||
def midi_msgs_to_minenote(
|
||||
@ -243,7 +242,6 @@ def midi_msgs_to_minenote(
|
||||
velocity_: int,
|
||||
start_time_: int,
|
||||
duration_: int,
|
||||
track_no_: int,
|
||||
play_speed: float,
|
||||
midi_reference_table: MidiInstrumentTableType,
|
||||
volume_processing_method_: Callable[[float], float],
|
||||
@ -254,9 +252,8 @@ def midi_msgs_to_minenote(
|
||||
:param note_: int 音高编号(音符编号)
|
||||
:param percussive_: bool 是否作为打击乐器启用
|
||||
:param velocity_: int 力度(响度)
|
||||
:param start_time_: int 音符起始时间(毫秒数)
|
||||
:param duration_: int 音符持续时间(毫秒数)
|
||||
:param track_no_: int 音符所处音轨
|
||||
:param start_time_: int 音符起始时间(微秒)
|
||||
:param duration_: int 音符持续时间(微秒)
|
||||
:param play_speed: float 曲目播放速度
|
||||
:param midi_reference_table: Dict[int, str] 转换对照表
|
||||
:param volume_proccessing_method_: Callable[[float], float] 音量处理函数
|
||||
@ -275,48 +272,47 @@ def midi_msgs_to_minenote(
|
||||
mc_sound_name=mc_sound_ID,
|
||||
midi_pitch=note_,
|
||||
midi_velocity=velocity_,
|
||||
start_time=round(start_time_ / float(play_speed) / 50),
|
||||
last_time=round(duration_ / float(play_speed) / 50),
|
||||
track_number=track_no_,
|
||||
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_,
|
||||
displacement=(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] 音量处理函数
|
||||
# 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",
|
||||
)
|
||||
# :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)
|
||||
# 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,
|
||||
)
|
||||
# return MineNote(
|
||||
# mc_sound_name=mc_sound_ID,
|
||||
# midi_pitch=note_.pitch,
|
||||
# midi_velocity=note_.velocity,
|
||||
# start_time=round(note_.start_time / float(play_speed) / 50),
|
||||
# last_time=round(note_.duration / float(play_speed) / 50),
|
||||
# is_percussion=note_.percussive,
|
||||
# displacement=(0, mc_distance_volume, 0),
|
||||
# extra_information=note_.extra_info,
|
||||
# )
|
||||
|
||||
|
||||
def is_in_diapason(note_pitch: int, instrument: str) -> bool:
|
||||
@ -337,7 +333,7 @@ def note_to_redstone_block(
|
||||
|
||||
Parameters
|
||||
----------
|
||||
note_: SingleNote
|
||||
note_: MineNote
|
||||
音符类
|
||||
random_select: bool
|
||||
是否随机选取对应方块
|
||||
|
@ -10,8 +10,12 @@ print(
|
||||
Musicreater.plugin.websocket.to_websocket_server(
|
||||
[
|
||||
Musicreater.MidiConvert.from_midi_file(
|
||||
os.path.join(dire,names), old_exe_format=False
|
||||
) for names in os.listdir(dire,) if names.endswith((".mid",".midi"))
|
||||
os.path.join(dire, names), old_exe_format=False
|
||||
)
|
||||
for names in os.listdir(
|
||||
dire,
|
||||
)
|
||||
if names.endswith((".mid", ".midi"))
|
||||
],
|
||||
input("服务器地址:"),
|
||||
int(input("服务器端口:")),
|
||||
|
Loading…
Reference in New Issue
Block a user