From b796a363d80d601e6fd8a6437659e0634de9b996 Mon Sep 17 00:00:00 2001 From: EillesWan Date: Wed, 20 Aug 2025 18:57:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E4=B8=B0=E5=AF=8C=E7=9A=84=E9=9F=B3?= =?UTF-8?q?=E7=AC=A6=E9=99=84=E5=8A=A0=E4=BF=A1=E6=81=AF=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Musicreater/__init__.py | 4 +-- Musicreater/experiment.py | 48 +++++++++++++++++++++++++----------- Musicreater/main.py | 12 ++++----- Musicreater/subclass.py | 51 ++++++++++++++++++++++++++++++++------- Musicreater/types.py | 11 +++++++-- Musicreater/utils.py | 18 +++++++------- 6 files changed, 102 insertions(+), 42 deletions(-) diff --git a/Musicreater/__init__.py b/Musicreater/__init__.py index 4f07f8e..fea4f7f 100644 --- a/Musicreater/__init__.py +++ b/Musicreater/__init__.py @@ -22,8 +22,8 @@ The Licensor of Musicreater("this project") is Eilles, bgArray. # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md -__version__ = "2.4.1" -__vername__ = "Midi 歌词支持,文档格式更新" +__version__ = "2.4.2" +__vername__ = "音符附加信息升级" __author__ = ( ("金羿", "Eilles"), ("诸葛亮与八卦阵", "bgArray"), diff --git a/Musicreater/experiment.py b/Musicreater/experiment.py index 33c024e..32b8e92 100644 --- a/Musicreater/experiment.py +++ b/Musicreater/experiment.py @@ -79,7 +79,7 @@ class FutureMidiConvertLyricSupport(MidiConvert): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -367,7 +367,7 @@ class FutureMidiConvertKamiRES(MidiConvert): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -446,7 +446,7 @@ class FutureMidiConvertKamiRES(MidiConvert): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -783,7 +783,7 @@ class FutureMidiConvertJavaE(MidiConvert): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -874,8 +874,14 @@ class FutureMidiConvertM4(MidiConvert): totalCount = int(_note.duration / _apply_time_division) - if totalCount == 0: - print(_note.extra_info) + if ( + totalCount == 0 + or (_note.get_info("PITCH") > 2 and _note.sound_name != "note.bass") + ): + from rich import print as prt + + prt("[INFO] 音符太短或音调太高,无法生成插值") + prt(_note) return [ _note, ] @@ -883,18 +889,24 @@ class FutureMidiConvertM4(MidiConvert): result: List[MineNote] = [] + _slide = _note.duration / totalCount + _distance_slide = 20 / totalCount + for _i in range(totalCount): result.append( MineNote( mc_sound_name=_note.sound_name, midi_pitch=_note.note_pitch, midi_velocity=_note.velocity, - start_time=int( - _note.start_tick + _i * (_note.duration / totalCount) - ), - last_time=int(_note.duration / totalCount), + start_time=int(_note.start_tick + _i * _slide), + last_time=int(_slide), # track_number=_note.track_no, is_percussion=_note.percussive, + distance=_note.sound_distance + _i * _distance_slide, + azimuth=( + _note.sound_azimuth[0], + _note.sound_azimuth[1] + 5 * random.random(), + ), extra_information=_note.extra_info, ) # ( @@ -931,14 +943,17 @@ class FutureMidiConvertM4(MidiConvert): for channel in self.channels.values(): for note in channel: note.set_info( - minenote_to_command_paramaters( + ["NOTE_ID", "COODINATES", "VOLUME", "PITCH"], + minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, - ) + ), ) if not note.percussive: - notes_list.extend(self._linear_note(note, 1 * note.extra_info[3])) + notes_list.extend( + self._linear_note(note, 2 * note.get_info("PITCH")) + ) else: notes_list.append(note) @@ -954,12 +969,17 @@ class FutureMidiConvertM4(MidiConvert): else: max_multi = max(max_multi, multi) multi = 0 + ( mc_sound_ID, relative_coordinates, volume_percentage, mc_pitch, - ) = note.extra_info + ) = minenote_to_command_parameters( + note, + pitch_deviation=self.music_deviation, + ) + self.music_command_list.append( MineCommand( command=( diff --git a/Musicreater/main.py b/Musicreater/main.py index e59b0a6..101f8e3 100644 --- a/Musicreater/main.py +++ b/Musicreater/main.py @@ -112,7 +112,7 @@ class MusicSequence: """ 音符序列类 - Paramaters + Parameters ========== name_of_music: str 乐曲名称 @@ -175,7 +175,7 @@ class MusicSequence: """ 自mido对象导入一个音符序列类 - Paramaters + Parameters ========== mido_file: mido.MidiFile 需要处理的midi对象 @@ -247,7 +247,7 @@ class MusicSequence: """ 从字节码导入音乐序列,目前支持 MSQ 第二、三、四版和 FSQ 第一、二版。 - Paramaters + Parameters ========== bytes_buffer_in: bytes 字节码 @@ -1588,7 +1588,7 @@ class MidiConvert(MusicSequence): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -1672,7 +1672,7 @@ class MidiConvert(MusicSequence): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) @@ -1758,7 +1758,7 @@ class MidiConvert(MusicSequence): relative_coordinates, volume_percentage, mc_pitch, - ) = minenote_to_command_paramaters( + ) = minenote_to_command_parameters( note, pitch_deviation=self.music_deviation, ) diff --git a/Musicreater/subclass.py b/Musicreater/subclass.py index 26a9ea3..27bdf02 100644 --- a/Musicreater/subclass.py +++ b/Musicreater/subclass.py @@ -18,7 +18,7 @@ Terms & Conditions: License.md in the root directory from math import sin, cos, asin, radians, degrees, sqrt, atan from dataclasses import dataclass -from typing import Optional, Any, List, Tuple, Union, Dict +from typing import Optional, Any, List, Tuple, Union, Dict, Sequence from .constants import MC_PITCHED_INSTRUMENT_LIST @@ -54,7 +54,7 @@ class MineNote: sound_azimuth: Tuple[float, float] """声源方位 角度""" - extra_info: Any + extra_info: Dict[str, Any] """你觉得放什么好?""" def __init__( @@ -68,7 +68,7 @@ class MineNote: is_percussion: Optional[bool] = None, distance: Optional[float] = None, azimuth: Optional[Tuple[float, float]] = None, - extra_information: Optional[Dict[str, Any]] = None, + extra_information: Dict[str, Any] = {}, ): """ 用于存储单个音符的类 @@ -98,7 +98,7 @@ class MineNote: 注:此参数为tuple,包含两个元素,分别表示: `rV` 发声源在竖直(上下)轴上,从玩家视角正前方开始,向顺时针旋转的角度 `rH` 发声源在水平(左右)轴上,从玩家视角正前方开始,向上(到达玩家正上方顶点后变为向下,以此类推的旋转)旋转的角度 - extra_information: Any + extra_information: Dict[str, Any] 附加信息,尽量存储为字典 Returns @@ -136,7 +136,7 @@ class MineNote: ) """声源距离""" - self.extra_info = extra_information + self.extra_info = extra_information if extra_information else {} @classmethod def from_traditional( @@ -210,7 +210,15 @@ class MineNote: is_percussion=is_percussion, distance=r, azimuth=(alpha_v, beta_h), - extra_information=extra_information, + extra_information=( + ( + extra_information + if isinstance(extra_information, dict) + else {"EXTRA_INFO": extra_information} + ) + if extra_information + else {} + ), ) @property @@ -225,7 +233,7 @@ class MineNote: @classmethod def decode(cls, code_buffer: bytes, is_high_time_precision: bool = True): - """自字节码析出MineNote类""" + """自字节码析出 MineNote 类""" group_1 = int.from_bytes(code_buffer[:6], "big") percussive_ = bool(group_1 & 0b1) duration_ = (group_1 := group_1 >> 1) & 0b11111111111111111 @@ -375,9 +383,34 @@ class MineNote: ) ) - def set_info(self, sth: Any): + def set_info(self, key: Union[str, Sequence[str]], value: Any): """设置附加信息""" - self.extra_info = sth + if isinstance(key, str): + self.extra_info[key] = value + elif ( + isinstance(key, Sequence) + and isinstance(value, Sequence) + and (k := len(key)) == len(value) + ): + for i in range(k): + self.extra_info[key[i]] = value[i] + else: + raise TypeError("参数类型错误") + + def get_info(self, key: str) -> Any: + """获取附加信息""" + if key in self.extra_info: + return self.extra_info[key] + elif "EXTRA_INFO" in self.extra_info: + if ( + isinstance(self.extra_info["EXTRA_INFO"], dict) + and key in self.extra_info["EXTRA_INFO"] + ): + return self.extra_info["EXTRA_INFO"].get(key) + else: + return self.extra_info["EXTRA_INFO"] + else: + return None def stringize( self, include_displacement: bool = False, include_extra_data: bool = False diff --git a/Musicreater/types.py b/Musicreater/types.py index eb5449a..16e6312 100644 --- a/Musicreater/types.py +++ b/Musicreater/types.py @@ -49,7 +49,7 @@ ChannelType = Dict[ ], ] """ -以字典所标记的频道信息类型(已弃用) +以字典所标记的通道信息类型(已弃用) Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],] """ @@ -60,7 +60,14 @@ MineNoteChannelType = Mapping[ List[MineNote,], ] """ -我的世界频道信息类型 +我的世界通道信息类型 Dict[int,Dict[int,List[MineNote,],],] """ + +MineNoteTrackType = Mapping[ + int, + List[MineNote,], +] + + diff --git a/Musicreater/utils.py b/Musicreater/utils.py index 509a909..af5d811 100644 --- a/Musicreater/utils.py +++ b/Musicreater/utils.py @@ -212,8 +212,8 @@ def panning_2_rotation_trigonometric(pan_: float) -> float: return math.degrees(math.acos((64 - pan_) / 63)) - 90 -def minenote_to_command_paramaters( - note_: MineNote, +def minenote_to_command_parameters( + mine_note: MineNote, pitch_deviation: float = 0, ) -> Tuple[ str, @@ -226,7 +226,7 @@ def minenote_to_command_paramaters( Parameters ------------ - note_: MineNote + mine_note: MineNote 音符对象 deviation: float 音调偏移量 @@ -238,19 +238,19 @@ def minenote_to_command_paramaters( """ return ( - note_.sound_name, - note_.position_displacement, - note_.velocity / 127, + mine_note.sound_name, + mine_note.position_displacement, + mine_note.velocity / 127, ( None - if note_.percussive + if mine_note.percussive else ( 2 ** ( ( - note_.note_pitch + mine_note.note_pitch - 60 - - MM_INSTRUMENT_DEVIATION_TABLE.get(note_.sound_name, 6) + - MM_INSTRUMENT_DEVIATION_TABLE.get(mine_note.sound_name, 6) + pitch_deviation ) / 12