mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2025-06-10 05:57:54 +00:00
MSQ 流式适配与校验增强,新增 NBS 音色表
This commit is contained in:
parent
889f8f9641
commit
c14489f3a7
@ -22,8 +22,8 @@ The Licensor of Musicreater("this project") is Eilles Wan, bgArray.
|
|||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
|
|
||||||
__version__ = "2.2.3"
|
__version__ = "2.2.4"
|
||||||
__vername__ = "Java版欲适配、初步MSQ流式适配"
|
__vername__ = "MSQ 流式适配与校验增强,新增 NBS 音色表"
|
||||||
__author__ = (
|
__author__ = (
|
||||||
("金羿", "Eilles"),
|
("金羿", "Eilles"),
|
||||||
("诸葛亮与八卦阵", "bgArray"),
|
("诸葛亮与八卦阵", "bgArray"),
|
||||||
@ -48,6 +48,14 @@ __all__ = [
|
|||||||
"MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE",
|
"MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE",
|
||||||
"MM_TOUCH_PITCHED_INSTRUMENT_TABLE",
|
"MM_TOUCH_PITCHED_INSTRUMENT_TABLE",
|
||||||
"MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE",
|
"MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE",
|
||||||
|
"MM_NBS_PITCHED_INSTRUMENT_TABLE",
|
||||||
|
"MM_NBS_PERCUSSION_INSTRUMENT_TABLE",
|
||||||
|
# 操作性函数
|
||||||
|
"natural_curve",
|
||||||
|
"straight_line",
|
||||||
|
"load_decode_msq_metainfo",
|
||||||
|
"load_decode_msq_flush_release",
|
||||||
|
"guess_deviation",
|
||||||
]
|
]
|
||||||
|
|
||||||
from .main import *
|
from .main import *
|
||||||
|
@ -16,7 +16,8 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# Email TriM-Organization@hotmail.com
|
# Email TriM-Organization@hotmail.com
|
||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
from .types import Dict, List, Tuple, MidiInstrumentTableType, MidiNoteNameTableType
|
# from .types import Dict, List, Tuple, MidiInstrumentTableType, MidiNoteNameTableType
|
||||||
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
x = "x"
|
x = "x"
|
||||||
"""
|
"""
|
||||||
@ -478,7 +479,12 @@ MM_INSTRUMENT_DEVIATION_TABLE: Dict[str, int] = {
|
|||||||
"fire.ignite": 0,
|
"fire.ignite": 0,
|
||||||
"note.cow_bell": 6,
|
"note.cow_bell": 6,
|
||||||
}
|
}
|
||||||
"""不同乐器的音调偏离对照表"""
|
"""
|
||||||
|
不同乐器的音调偏离对照表
|
||||||
|
*注意* 该表中的单位是对于 Midi Pitch 音调(整数)的低音偏移。
|
||||||
|
也就是说,该数值越高,则在 Midi Pitch 中的值域越低
|
||||||
|
默认的偏移量为 6 ,因为在计算音高时候少减去了 6 个 Pitch 单位
|
||||||
|
"""
|
||||||
|
|
||||||
# Midi乐器对MC乐器对照表
|
# Midi乐器对MC乐器对照表
|
||||||
|
|
||||||
@ -853,6 +859,8 @@ MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE: Dict[int, str] = {
|
|||||||
"""“偷吃”打击乐器对照表"""
|
"""“偷吃”打击乐器对照表"""
|
||||||
|
|
||||||
# Dislink “断联” 音色对照表
|
# Dislink “断联” 音色对照表
|
||||||
|
# https://github.com/Dislink/midi2bdx/blob/main/index.html
|
||||||
|
|
||||||
|
|
||||||
MM_DISLINK_PITCHED_INSTRUMENT_TABLE: Dict[int, str] = {
|
MM_DISLINK_PITCHED_INSTRUMENT_TABLE: Dict[int, str] = {
|
||||||
0: "note.harp",
|
0: "note.harp",
|
||||||
@ -1037,6 +1045,210 @@ MM_DISLINK_PERCUSSION_INSTRUMENT_TABLE: Dict[int, str] = {
|
|||||||
}
|
}
|
||||||
"""“断联”打击乐器对照表"""
|
"""“断联”打击乐器对照表"""
|
||||||
|
|
||||||
|
# NoteBlockStudio “NBS”音色对照表
|
||||||
|
# https://github.com/OpenNBS/NoteBlockStudio/blob/main/scripts/midi_instruments/midi_instruments.gml
|
||||||
|
|
||||||
|
MM_NBS_PITCHED_INSTRUMENT_TABLE: Dict[int, str] = {
|
||||||
|
0: "note.harp",
|
||||||
|
1: "note.pling",
|
||||||
|
2: "note.harp",
|
||||||
|
3: "note.pling",
|
||||||
|
4: "note.harp",
|
||||||
|
5: "note.harp",
|
||||||
|
6: "note.guitar",
|
||||||
|
7: "note.banjo",
|
||||||
|
8: "note.bell",
|
||||||
|
9: "note.bell",
|
||||||
|
10: "note.bell",
|
||||||
|
11: "note.iron_xylophone",
|
||||||
|
12: "note.iron_xylophone",
|
||||||
|
13: "note.xylophone",
|
||||||
|
14: "note.bell",
|
||||||
|
15: "note.iron_xylophone",
|
||||||
|
16: "note.flute",
|
||||||
|
17: "note.flute",
|
||||||
|
18: "note.flute",
|
||||||
|
19: "note.flute",
|
||||||
|
20: "note.flute",
|
||||||
|
21: "note.flute",
|
||||||
|
22: "note.flute",
|
||||||
|
23: "note.flute",
|
||||||
|
24: "note.guitar",
|
||||||
|
25: "note.guitar",
|
||||||
|
26: "note.guitar",
|
||||||
|
27: "note.bass",
|
||||||
|
28: "note.guitar",
|
||||||
|
29: "note.guitar",
|
||||||
|
30: "note.bass",
|
||||||
|
31: "note.bass",
|
||||||
|
32: "note.bass",
|
||||||
|
33: "note.guitar",
|
||||||
|
34: "note.guitar",
|
||||||
|
35: "note.bass",
|
||||||
|
36: "note.pling",
|
||||||
|
37: "note.flute",
|
||||||
|
38: "note.flute",
|
||||||
|
39: "note.flute",
|
||||||
|
40: "note.flute",
|
||||||
|
41: "note.flute",
|
||||||
|
42: "note.didgeridoo",
|
||||||
|
43: "note.flute",
|
||||||
|
44: "note.didgeridoo",
|
||||||
|
45: "note.flute",
|
||||||
|
46: "note.flute",
|
||||||
|
47: "note.flute",
|
||||||
|
48: "note.flute",
|
||||||
|
49: "note.flute",
|
||||||
|
50: "note.flute",
|
||||||
|
51: "note.flute",
|
||||||
|
52: "note.flute",
|
||||||
|
53: "note.flute",
|
||||||
|
54: "note.flute",
|
||||||
|
55: "note.flute",
|
||||||
|
56: "note.flute",
|
||||||
|
57: "note.flute",
|
||||||
|
58: "note.flute",
|
||||||
|
59: "note.flute",
|
||||||
|
60: "note.bit",
|
||||||
|
61: "note.flute",
|
||||||
|
62: "note.flute",
|
||||||
|
63: "note.flute",
|
||||||
|
64: "note.flute",
|
||||||
|
65: "note.guitar",
|
||||||
|
66: "note.flute",
|
||||||
|
67: "note.flute",
|
||||||
|
68: "note.flute",
|
||||||
|
69: "note.bell",
|
||||||
|
70: "note.flute",
|
||||||
|
71: "note.flute",
|
||||||
|
72: "note.flute",
|
||||||
|
73: "note.flute",
|
||||||
|
74: "note.chime",
|
||||||
|
75: "note.flute",
|
||||||
|
76: "note.flute",
|
||||||
|
77: "note.guitar",
|
||||||
|
78: "note.pling",
|
||||||
|
79: "note.flute",
|
||||||
|
80: "note.guitar",
|
||||||
|
81: "note.banjo",
|
||||||
|
82: "note.banjo",
|
||||||
|
83: "note.banjo",
|
||||||
|
84: "note.guitar",
|
||||||
|
85: "note.iron_xylophone",
|
||||||
|
86: "note.flute",
|
||||||
|
87: "note.flute",
|
||||||
|
88: "note.chime",
|
||||||
|
89: "note.cow_bell",
|
||||||
|
90: "note.iron_xylophone",
|
||||||
|
91: "note.xylophone",
|
||||||
|
92: "note.basedrum",
|
||||||
|
93: "note.snare",
|
||||||
|
94: "note.snare",
|
||||||
|
95: "note.basedrum",
|
||||||
|
96: "note.snare",
|
||||||
|
97: "note.hat",
|
||||||
|
98: "note.snare",
|
||||||
|
99: "note.hat",
|
||||||
|
100: "note.basedrum",
|
||||||
|
101: "note.hat",
|
||||||
|
102: "note.basedrum",
|
||||||
|
103: "note.hat",
|
||||||
|
104: "note.basedrum",
|
||||||
|
105: "note.snare",
|
||||||
|
106: "note.snare",
|
||||||
|
107: "note.snare",
|
||||||
|
108: "note.cow_bell",
|
||||||
|
109: "note.snare",
|
||||||
|
110: "note.hat",
|
||||||
|
111: "note.snare",
|
||||||
|
112: "note.hat",
|
||||||
|
113: "note.hat",
|
||||||
|
114: "note.hat",
|
||||||
|
115: "note.hat",
|
||||||
|
116: "note.hat",
|
||||||
|
117: "note.chime",
|
||||||
|
118: "note.hat",
|
||||||
|
119: "note.snare",
|
||||||
|
120: "note.hat",
|
||||||
|
121: "note.hat",
|
||||||
|
122: "note.hat",
|
||||||
|
123: "note.hat",
|
||||||
|
124: "note.hat",
|
||||||
|
125: "note.snare",
|
||||||
|
126: "note.basedrum",
|
||||||
|
127: "note.basedrum",
|
||||||
|
}
|
||||||
|
"""“NBS”乐音乐器对照表"""
|
||||||
|
|
||||||
|
|
||||||
|
MM_NBS_PERCUSSION_INSTRUMENT_TABLE: Dict[int, str] = {
|
||||||
|
24: "note.bit",
|
||||||
|
25: "note.snare",
|
||||||
|
26: "note.hat",
|
||||||
|
27: "note.snare",
|
||||||
|
28: "note.snare",
|
||||||
|
29: "note.hat",
|
||||||
|
30: "note.hat",
|
||||||
|
31: "note.hat",
|
||||||
|
32: "note.hat",
|
||||||
|
33: "note.hat",
|
||||||
|
34: "note.chime",
|
||||||
|
35: "note.basedrum",
|
||||||
|
36: "note.basedrum",
|
||||||
|
37: "note.hat",
|
||||||
|
38: "note.snare",
|
||||||
|
39: "note.hat",
|
||||||
|
40: "note.snare",
|
||||||
|
41: "note.basedrum",
|
||||||
|
42: "note.snare",
|
||||||
|
43: "note.basedrum",
|
||||||
|
44: "note.snare",
|
||||||
|
45: "note.basedrum",
|
||||||
|
46: "note.basedrum",
|
||||||
|
47: "note.snare",
|
||||||
|
48: "note.snare",
|
||||||
|
49: "note.snare",
|
||||||
|
50: "note.snare",
|
||||||
|
51: "note.snare",
|
||||||
|
52: "note.snare",
|
||||||
|
53: "note.hat",
|
||||||
|
54: "note.snare",
|
||||||
|
55: "note.snare",
|
||||||
|
56: "note.cow_bell",
|
||||||
|
57: "note.snare",
|
||||||
|
58: "note.hat",
|
||||||
|
59: "note.snare",
|
||||||
|
60: "note.hat",
|
||||||
|
61: "note.hat",
|
||||||
|
62: "note.hat",
|
||||||
|
63: "note.basedrum",
|
||||||
|
64: "note.basedrum",
|
||||||
|
65: "note.snare",
|
||||||
|
66: "note.snare",
|
||||||
|
67: "note.xylophone",
|
||||||
|
68: "note.xylophone",
|
||||||
|
69: "note.hat",
|
||||||
|
70: "note.hat",
|
||||||
|
71: "note.flute",
|
||||||
|
72: "note.flute",
|
||||||
|
73: "note.hat",
|
||||||
|
74: "note.hat",
|
||||||
|
75: "note.hat",
|
||||||
|
76: "note.hat",
|
||||||
|
77: "note.hat",
|
||||||
|
78: "note.didgeridoo",
|
||||||
|
79: "note.didgeridoo",
|
||||||
|
80: "note.hat",
|
||||||
|
81: "note.chime",
|
||||||
|
82: "note.hat",
|
||||||
|
83: "note.chime",
|
||||||
|
84: "note.chime",
|
||||||
|
85: "note.hat",
|
||||||
|
86: "note.basedrum",
|
||||||
|
87: "note.basedrum",
|
||||||
|
}
|
||||||
|
"""“NBS”打击乐器对照表"""
|
||||||
|
|
||||||
# Midi音高对MC方块对照表
|
# Midi音高对MC方块对照表
|
||||||
|
|
||||||
# 金羿ELS 音符方块对照表
|
# 金羿ELS 音符方块对照表
|
||||||
|
@ -34,7 +34,6 @@ import os
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
import mido
|
import mido
|
||||||
from xxhash import xxh3_64, xxh3_128
|
|
||||||
|
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
@ -169,6 +168,7 @@ class MusicSequence:
|
|||||||
minimum_vol: float = 0.1,
|
minimum_vol: float = 0.1,
|
||||||
volume_processing_function: FittingFunctionType = natural_curve,
|
volume_processing_function: FittingFunctionType = natural_curve,
|
||||||
deviation: float = 0,
|
deviation: float = 0,
|
||||||
|
note_referance_table_replacement: Dict[str, str] = {},
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
自mido对象导入一个音符序列类
|
自mido对象导入一个音符序列类
|
||||||
@ -210,6 +210,7 @@ class MusicSequence:
|
|||||||
default_tempo_value=default_tempo,
|
default_tempo_value=default_tempo,
|
||||||
vol_processing_function=volume_processing_function,
|
vol_processing_function=volume_processing_function,
|
||||||
ignore_mismatch_error=mismatch_error_ignorance,
|
ignore_mismatch_error=mismatch_error_ignorance,
|
||||||
|
note_rtable_replacement=note_referance_table_replacement,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
note_channels = {}
|
note_channels = {}
|
||||||
@ -241,6 +242,7 @@ class MusicSequence:
|
|||||||
music_name_ = bytes_buffer_in[8 : (stt_index := 8 + (group_1 >> 10))].decode(
|
music_name_ = bytes_buffer_in[8 : (stt_index := 8 + (group_1 >> 10))].decode(
|
||||||
"GB18030"
|
"GB18030"
|
||||||
)
|
)
|
||||||
|
|
||||||
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
channels_: MineNoteChannelType = empty_midi_channels(default_staff=[])
|
||||||
total_note_count = 0
|
total_note_count = 0
|
||||||
if verify:
|
if verify:
|
||||||
@ -477,8 +479,11 @@ class MusicSequence:
|
|||||||
"""重命名此音乐"""
|
"""重命名此音乐"""
|
||||||
self.music_name = new_name
|
self.music_name = new_name
|
||||||
|
|
||||||
def add_note(self, channel_no: int, note: MineNote, is_sort: bool = False):
|
def add_note(self, channel_no: int, note: MineNote, is_sort: bool = True):
|
||||||
"""在指定通道添加一个音符"""
|
"""
|
||||||
|
在指定通道添加一个音符
|
||||||
|
值得注意:在版本 2.2.3 及之前 is_sort 参数默认为 False ;在此之后为 True
|
||||||
|
"""
|
||||||
self.channels[channel_no].append(note)
|
self.channels[channel_no].append(note)
|
||||||
self.total_note_count += 1
|
self.total_note_count += 1
|
||||||
if note.sound_name in self.note_count_per_instrument.keys():
|
if note.sound_name in self.note_count_per_instrument.keys():
|
||||||
@ -498,6 +503,7 @@ class MusicSequence:
|
|||||||
pitched_note_rtable: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
|
pitched_note_rtable: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
|
||||||
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
|
||||||
vol_processing_function: FittingFunctionType = natural_curve,
|
vol_processing_function: FittingFunctionType = natural_curve,
|
||||||
|
note_rtable_replacement: Dict[str, str] = {},
|
||||||
) -> Tuple[MineNoteChannelType, int, Dict[str, int]]:
|
) -> Tuple[MineNoteChannelType, int, Dict[str, int]]:
|
||||||
"""
|
"""
|
||||||
将midi解析并转换为频道音符字典
|
将midi解析并转换为频道音符字典
|
||||||
@ -616,6 +622,7 @@ class MusicSequence:
|
|||||||
else pitched_note_rtable
|
else pitched_note_rtable
|
||||||
),
|
),
|
||||||
volume_processing_method_=vol_processing_function,
|
volume_processing_method_=vol_processing_function,
|
||||||
|
note_table_replacement=note_rtable_replacement,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
note_count += 1
|
note_count += 1
|
||||||
@ -693,6 +700,7 @@ class MidiConvert(MusicSequence):
|
|||||||
enable_old_exe_format: bool = False,
|
enable_old_exe_format: bool = False,
|
||||||
minimum_volume: float = 0.1,
|
minimum_volume: float = 0.1,
|
||||||
vol_processing_function: FittingFunctionType = natural_curve,
|
vol_processing_function: FittingFunctionType = natural_curve,
|
||||||
|
note_rtable_replacement: Dict[str, str] = {},
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
简单的midi转换类,将midi对象转换为我的世界结构或者包
|
简单的midi转换类,将midi对象转换为我的世界结构或者包
|
||||||
@ -742,6 +750,7 @@ class MidiConvert(MusicSequence):
|
|||||||
volume_processing_function=vol_processing_function,
|
volume_processing_function=vol_processing_function,
|
||||||
default_tempo=default_tempo_value,
|
default_tempo=default_tempo_value,
|
||||||
mismatch_error_ignorance=ignore_mismatch_error,
|
mismatch_error_ignorance=ignore_mismatch_error,
|
||||||
|
note_referance_table_replacement=note_rtable_replacement,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -756,6 +765,7 @@ class MidiConvert(MusicSequence):
|
|||||||
old_exe_format: bool = False,
|
old_exe_format: bool = False,
|
||||||
min_volume: float = 0.1,
|
min_volume: float = 0.1,
|
||||||
vol_processing_func: FittingFunctionType = natural_curve,
|
vol_processing_func: FittingFunctionType = natural_curve,
|
||||||
|
note_table_replacement: Dict[str, str] = {},
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
直接输入文件地址,将midi文件读入
|
直接输入文件地址,将midi文件读入
|
||||||
@ -802,6 +812,7 @@ class MidiConvert(MusicSequence):
|
|||||||
enable_old_exe_format=old_exe_format,
|
enable_old_exe_format=old_exe_format,
|
||||||
minimum_volume=min_volume,
|
minimum_volume=min_volume,
|
||||||
vol_processing_function=vol_processing_func,
|
vol_processing_function=vol_processing_func,
|
||||||
|
note_rtable_replacement=note_table_replacement,
|
||||||
)
|
)
|
||||||
except (ValueError, TypeError) as E:
|
except (ValueError, TypeError) as E:
|
||||||
raise MidiDestroyedError(f"文件{midi_file_path}可能损坏:{E}")
|
raise MidiDestroyedError(f"文件{midi_file_path}可能损坏:{E}")
|
||||||
|
@ -18,9 +18,9 @@ Terms & Conditions: License.md in the root directory
|
|||||||
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from .types import Optional, Any, List, Mapping, Tuple, Union
|
from typing import Optional, Any, List, Tuple, Union
|
||||||
|
|
||||||
from .constants import MC_PERCUSSION_INSTRUMENT_LIST
|
from .constants import MC_PITCHED_INSTRUMENT_LIST
|
||||||
|
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
@ -91,7 +91,7 @@ class MineNote:
|
|||||||
"""高精度开始时间偏量 0.4 毫秒"""
|
"""高精度开始时间偏量 0.4 毫秒"""
|
||||||
|
|
||||||
self.percussive = (
|
self.percussive = (
|
||||||
(mc_sound_name in MC_PERCUSSION_INSTRUMENT_LIST)
|
(mc_sound_name not in MC_PITCHED_INSTRUMENT_LIST)
|
||||||
if (is_percussion is None)
|
if (is_percussion is None)
|
||||||
else is_percussion
|
else is_percussion
|
||||||
)
|
)
|
||||||
@ -463,7 +463,7 @@ class SingleNoteBox:
|
|||||||
self.annotation_text = annotation
|
self.annotation_text = annotation
|
||||||
"""音符注释"""
|
"""音符注释"""
|
||||||
if percussion is None:
|
if percussion is None:
|
||||||
self.is_percussion = percussion in MC_PERCUSSION_INSTRUMENT_LIST
|
self.is_percussion = percussion not in MC_PITCHED_INSTRUMENT_LIST
|
||||||
else:
|
else:
|
||||||
self.is_percussion = percussion
|
self.is_percussion = percussion
|
||||||
|
|
||||||
@ -653,14 +653,3 @@ DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle(
|
|||||||
"""
|
"""
|
||||||
默认的进度条样式
|
默认的进度条样式
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
MineNoteChannelType = Mapping[
|
|
||||||
int,
|
|
||||||
List[MineNote,],
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
我的世界频道信息类型
|
|
||||||
|
|
||||||
Dict[int,Dict[int,List[MineNote,],],]
|
|
||||||
"""
|
|
||||||
|
@ -17,19 +17,17 @@ Terms & Conditions: License.md in the root directory
|
|||||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||||
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
Literal,
|
Literal,
|
||||||
Optional,
|
|
||||||
Tuple,
|
Tuple,
|
||||||
Union,
|
Union,
|
||||||
Iterable,
|
|
||||||
Sequence,
|
|
||||||
Mapping,
|
Mapping,
|
||||||
Callable,
|
Callable,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .subclass import MineNote
|
||||||
|
|
||||||
|
|
||||||
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
|
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
|
||||||
"""
|
"""
|
||||||
@ -64,3 +62,14 @@ ChannelType = Dict[
|
|||||||
|
|
||||||
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
|
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
MineNoteChannelType = Mapping[
|
||||||
|
int,
|
||||||
|
List[MineNote,],
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
我的世界频道信息类型
|
||||||
|
|
||||||
|
Dict[int,Dict[int,List[MineNote,],],]
|
||||||
|
"""
|
||||||
|
@ -18,6 +18,22 @@ Terms & Conditions: License.md in the root directory
|
|||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
# from io import BytesIO
|
||||||
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Dict,
|
||||||
|
Tuple,
|
||||||
|
Optional,
|
||||||
|
Callable,
|
||||||
|
Literal,
|
||||||
|
Union,
|
||||||
|
List,
|
||||||
|
Generator,
|
||||||
|
BinaryIO,
|
||||||
|
)
|
||||||
|
|
||||||
|
from xxhash import xxh3_64, xxh3_128
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
MC_INSTRUMENT_BLOCKS_TABLE,
|
MC_INSTRUMENT_BLOCKS_TABLE,
|
||||||
MM_INSTRUMENT_DEVIATION_TABLE,
|
MM_INSTRUMENT_DEVIATION_TABLE,
|
||||||
@ -26,16 +42,9 @@ from .constants import (
|
|||||||
)
|
)
|
||||||
from .subclass import MineNote, mctick2timestr
|
from .subclass import MineNote, mctick2timestr
|
||||||
|
|
||||||
from .types import (
|
from .types import MidiInstrumentTableType, MineNoteChannelType
|
||||||
Any,
|
|
||||||
Dict,
|
from .exceptions import MusicSequenceDecodeError
|
||||||
Tuple,
|
|
||||||
Optional,
|
|
||||||
Callable,
|
|
||||||
Literal,
|
|
||||||
Union,
|
|
||||||
MidiInstrumentTableType,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def empty_midi_channels(
|
def empty_midi_channels(
|
||||||
@ -251,6 +260,7 @@ def midi_msgs_to_minenote(
|
|||||||
play_speed: float,
|
play_speed: float,
|
||||||
midi_reference_table: MidiInstrumentTableType,
|
midi_reference_table: MidiInstrumentTableType,
|
||||||
volume_processing_method_: Callable[[float], float],
|
volume_processing_method_: Callable[[float], float],
|
||||||
|
note_table_replacement: Dict[str, str] = {},
|
||||||
) -> MineNote:
|
) -> MineNote:
|
||||||
"""
|
"""
|
||||||
将Midi信息转为我的世界音符对象
|
将Midi信息转为我的世界音符对象
|
||||||
@ -275,7 +285,7 @@ def midi_msgs_to_minenote(
|
|||||||
mc_distance_volume = volume_processing_method_(velocity_)
|
mc_distance_volume = volume_processing_method_(velocity_)
|
||||||
|
|
||||||
return MineNote(
|
return MineNote(
|
||||||
mc_sound_name=mc_sound_ID,
|
mc_sound_name=note_table_replacement.get(mc_sound_ID, mc_sound_ID),
|
||||||
midi_pitch=note_,
|
midi_pitch=note_,
|
||||||
midi_velocity=velocity_,
|
midi_velocity=velocity_,
|
||||||
start_time=(tk := int(start_time_ / float(play_speed) / 50000)),
|
start_time=(tk := int(start_time_ / float(play_speed) / 50000)),
|
||||||
@ -378,3 +388,291 @@ def soundID_to_blockID(
|
|||||||
return random.choice(MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,)))
|
return random.choice(MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,)))
|
||||||
else:
|
else:
|
||||||
return MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,))[0]
|
return MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,))[0]
|
||||||
|
|
||||||
|
|
||||||
|
def load_decode_msq_metainfo(
|
||||||
|
buffer_in: BinaryIO,
|
||||||
|
) -> Tuple[str, float, float, bool, int]:
|
||||||
|
"""
|
||||||
|
以流的方式解码MSQ音乐序列元信息
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
buffer_in: BytesIO
|
||||||
|
MSQ格式的字节流
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Tuple[str, float, float, bool, int]
|
||||||
|
音乐名称,最小音量,音调偏移,是否启用高精度,最后的流指针位置
|
||||||
|
|
||||||
|
"""
|
||||||
|
buffer_in.seek(4, 0)
|
||||||
|
group_1 = int.from_bytes(buffer_in.read(2), "big")
|
||||||
|
group_2 = int.from_bytes(buffer_in.read(2), "big", signed=False)
|
||||||
|
|
||||||
|
# high_quantity = bool(group_2 & 0b1000000000000000)
|
||||||
|
# print(group_2, high_quantity)
|
||||||
|
|
||||||
|
music_name_ = buffer_in.read(stt_index := (group_1 >> 10)).decode("GB18030")
|
||||||
|
|
||||||
|
return (
|
||||||
|
music_name_,
|
||||||
|
(group_1 & 0b1111111111) / 1000,
|
||||||
|
(
|
||||||
|
(-1 if group_2 & 0b100000000000000 else 1)
|
||||||
|
* (group_2 & 0b11111111111111)
|
||||||
|
/ 1000
|
||||||
|
),
|
||||||
|
bool(group_2 & 0b1000000000000000),
|
||||||
|
stt_index + 8,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_decode_msq_flush_release(
|
||||||
|
buffer_in: BinaryIO,
|
||||||
|
starter_index: int,
|
||||||
|
high_quantity_note: bool,
|
||||||
|
) -> Generator[Tuple[int, MineNote], Any, None]:
|
||||||
|
"""以流的方式解码MSQ音乐序列的音符序列并流式返回
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
buffer_in : BytesIO
|
||||||
|
输入的MSQ格式二进制字节流
|
||||||
|
starter_index : int
|
||||||
|
字节流中,音符序列的起始索引
|
||||||
|
high_quantity_note : bool
|
||||||
|
是否启用高精度音符解析
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Generator[Tuple[int, MineNote], Any, None]
|
||||||
|
以流的方式返回解码后的音符序列
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
MusicSequenceDecodeError
|
||||||
|
当解码过程中出现错误,抛出异常
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# _total_verify = xxh3_64(buffer_in.read(starter_index), seed=total_note_count)
|
||||||
|
|
||||||
|
# buffer_in.seek(starter_index, 0)
|
||||||
|
buffer_in.seek(starter_index)
|
||||||
|
_bytes_buffer_in = buffer_in.read()
|
||||||
|
# int.from_bytes(_bytes_buffer_in[0 : 4], "big")
|
||||||
|
|
||||||
|
_now_channel_starter_index = 0
|
||||||
|
|
||||||
|
_total_note_count = 1
|
||||||
|
|
||||||
|
_channel_infos = empty_midi_channels(
|
||||||
|
default_staff={"NOW_INDEX": 0, "NOTE_COUNT": 0, "HAVE_READ": 0, "END_INDEX": -1}
|
||||||
|
)
|
||||||
|
|
||||||
|
for __channel_index in _channel_infos.keys():
|
||||||
|
# _channel_note_count = 0
|
||||||
|
|
||||||
|
_now_channel_ender_sign = xxh3_64(
|
||||||
|
_bytes_buffer_in[
|
||||||
|
_now_channel_starter_index : _now_channel_starter_index + 4
|
||||||
|
],
|
||||||
|
seed=3,
|
||||||
|
).digest()
|
||||||
|
|
||||||
|
# print(
|
||||||
|
# "[DEBUG] 索引取得:",
|
||||||
|
# _bytes_buffer_in[
|
||||||
|
# _now_channel_starter_index : _now_channel_starter_index + 4
|
||||||
|
# ],
|
||||||
|
# "校验索引",
|
||||||
|
# _now_channel_ender_sign,
|
||||||
|
# )
|
||||||
|
|
||||||
|
_now_channel_ender_index = _bytes_buffer_in.find(_now_channel_ender_sign)
|
||||||
|
|
||||||
|
# print("[DEBUG] 索引取得:", _now_channel_ender_index,)
|
||||||
|
|
||||||
|
_channel_note_count = int.from_bytes(
|
||||||
|
_bytes_buffer_in[
|
||||||
|
_now_channel_starter_index : _now_channel_starter_index + 4
|
||||||
|
],
|
||||||
|
"big",
|
||||||
|
)
|
||||||
|
|
||||||
|
if _channel_note_count == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
while (
|
||||||
|
xxh3_64(
|
||||||
|
_bytes_buffer_in[_now_channel_starter_index:_now_channel_ender_index],
|
||||||
|
seed=_channel_note_count,
|
||||||
|
).digest()
|
||||||
|
!= _bytes_buffer_in[
|
||||||
|
_now_channel_ender_index + 8 : _now_channel_ender_index + 16
|
||||||
|
]
|
||||||
|
):
|
||||||
|
_now_channel_ender_index += 8 + _bytes_buffer_in[
|
||||||
|
_now_channel_ender_index + 8 :
|
||||||
|
].find(_now_channel_ender_sign)
|
||||||
|
|
||||||
|
# print(
|
||||||
|
# "[WARNING] XXHASH 无法匹配,当前序列",
|
||||||
|
# __channel_index,
|
||||||
|
# "当前全部序列字节串",
|
||||||
|
# _bytes_buffer_in[
|
||||||
|
# _now_channel_starter_index:_now_channel_ender_index
|
||||||
|
# ],
|
||||||
|
# "校验值",
|
||||||
|
# xxh3_64(
|
||||||
|
# _bytes_buffer_in[
|
||||||
|
# _now_channel_starter_index:_now_channel_ender_index
|
||||||
|
# ],
|
||||||
|
# seed=_channel_note_count,
|
||||||
|
# ).digest(),
|
||||||
|
# _bytes_buffer_in[
|
||||||
|
# _now_channel_ender_index + 8 : _now_channel_ender_index + 16
|
||||||
|
# ],
|
||||||
|
# "改变结尾索引",
|
||||||
|
# _now_channel_ender_index,
|
||||||
|
# )
|
||||||
|
|
||||||
|
_channel_infos[__channel_index]["NOW_INDEX"] = _now_channel_starter_index + 4
|
||||||
|
_channel_infos[__channel_index]["END_INDEX"] = _now_channel_ender_index
|
||||||
|
_channel_infos[__channel_index]["NOTE_COUNT"] = _channel_note_count
|
||||||
|
|
||||||
|
# print(
|
||||||
|
# "[DEBUG] 当前序列", __channel_index, "值", _channel_infos[__channel_index]
|
||||||
|
# )
|
||||||
|
|
||||||
|
_total_note_count += _channel_note_count
|
||||||
|
|
||||||
|
_now_channel_starter_index = _now_channel_ender_index + 16
|
||||||
|
# for i in range(
|
||||||
|
# int.from_bytes(
|
||||||
|
# bytes_buffer_in[stt_index : (stt_index := stt_index + 4)], "big"
|
||||||
|
# )
|
||||||
|
# ):
|
||||||
|
_to_yield_note_list: List[Tuple[MineNote, int]] = []
|
||||||
|
|
||||||
|
# {"NOW_INDEX": 0, "NOTE_COUNT": 0, "HAVE_READ": 0, "END_INDEX": -1}
|
||||||
|
|
||||||
|
while _total_note_count:
|
||||||
|
_read_in_note_list: List[Tuple[MineNote, int]] = []
|
||||||
|
for __channel_index in _channel_infos.keys():
|
||||||
|
if (
|
||||||
|
_channel_infos[__channel_index]["HAVE_READ"]
|
||||||
|
< _channel_infos[__channel_index]["NOTE_COUNT"]
|
||||||
|
):
|
||||||
|
# print("当前已读", _channel_infos[__channel_index]["HAVE_READ"])
|
||||||
|
try:
|
||||||
|
_end_index = (
|
||||||
|
(_stt_index := _channel_infos[__channel_index]["NOW_INDEX"])
|
||||||
|
+ 13
|
||||||
|
+ high_quantity_note
|
||||||
|
+ (_bytes_buffer_in[_stt_index] >> 2)
|
||||||
|
)
|
||||||
|
# print("读取音符字节串", _bytes_buffer_in[_stt_index:_end_index])
|
||||||
|
_read_in_note_list.append(
|
||||||
|
(
|
||||||
|
MineNote.decode(
|
||||||
|
code_buffer=_bytes_buffer_in[_stt_index:_end_index],
|
||||||
|
is_high_time_precision=high_quantity_note,
|
||||||
|
),
|
||||||
|
__channel_index,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
_channel_infos[__channel_index]["HAVE_READ"] += 1
|
||||||
|
_channel_infos[__channel_index]["NOW_INDEX"] = _end_index
|
||||||
|
_total_note_count -= 1
|
||||||
|
except Exception as _err:
|
||||||
|
# print(channels_)
|
||||||
|
raise MusicSequenceDecodeError("难以定位的解码错误", _err)
|
||||||
|
if not _read_in_note_list:
|
||||||
|
break
|
||||||
|
# _note_list.append
|
||||||
|
min_stt_note: MineNote = min(_read_in_note_list, key=lambda x: x[0].start_tick)[
|
||||||
|
0
|
||||||
|
]
|
||||||
|
for i in range(len(_to_yield_note_list)):
|
||||||
|
__note, __channel_index = _to_yield_note_list[i]
|
||||||
|
if __note.start_tick >= min_stt_note.start_tick:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
yield __channel_index, __note
|
||||||
|
_to_yield_note_list.pop(i)
|
||||||
|
|
||||||
|
_to_yield_note_list.extend(_read_in_note_list)
|
||||||
|
_to_yield_note_list.sort(key=lambda x: x[0].start_tick)
|
||||||
|
|
||||||
|
for __note, __channel_index in sorted(
|
||||||
|
_to_yield_note_list, key=lambda x: x[0].start_tick
|
||||||
|
):
|
||||||
|
yield __channel_index, __note
|
||||||
|
# 俺寻思能用
|
||||||
|
|
||||||
|
|
||||||
|
def guess_deviation(
|
||||||
|
total_note_count: int,
|
||||||
|
total_instrument_count: int,
|
||||||
|
note_count_per_instrument: Optional[Dict[str, int]] = None,
|
||||||
|
qualified_note_count_per_instrument: Optional[Dict[str, int]] = None,
|
||||||
|
music_channels: Optional[MineNoteChannelType] = None,
|
||||||
|
) -> float:
|
||||||
|
"""
|
||||||
|
通过乐器权重来计算一首歌的音调偏移
|
||||||
|
这个方法未经验证,但理论有效,金羿首创
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
total_note_count: int
|
||||||
|
歌曲总音符数
|
||||||
|
total_instrument_count: int
|
||||||
|
歌曲乐器总数
|
||||||
|
note_count_per_instrument: Dict[str, int]
|
||||||
|
乐器名称与乐器音符数对照表
|
||||||
|
qualified_note_count_per_instrument: Dict[str, int]
|
||||||
|
每个乐器中,符合该乐器的音调范围的音符数
|
||||||
|
music_channels: MineNoteChannelType
|
||||||
|
MusicSequence类的音乐通道字典
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float估测的音调偏移值
|
||||||
|
"""
|
||||||
|
if note_count_per_instrument is None or qualified_note_count_per_instrument is None:
|
||||||
|
if music_channels is None:
|
||||||
|
raise ValueError("参数不足,算逑!")
|
||||||
|
note_count_per_instrument = {}
|
||||||
|
qualified_note_count_per_instrument = {}
|
||||||
|
for this_note in [k for j in music_channels.values() for k in j]:
|
||||||
|
if this_note.sound_name in note_count_per_instrument.keys():
|
||||||
|
note_count_per_instrument[this_note.sound_name] += 1
|
||||||
|
qualified_note_count_per_instrument[
|
||||||
|
this_note.sound_name
|
||||||
|
] += is_note_in_diapason(this_note)
|
||||||
|
else:
|
||||||
|
note_count_per_instrument[this_note.sound_name] = 1
|
||||||
|
qualified_note_count_per_instrument[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_instrument[inst])
|
||||||
|
)
|
||||||
|
for inst, note_count in note_count_per_instrument.items()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
/ total_instrument_count
|
||||||
|
/ total_note_count
|
||||||
|
)
|
||||||
|
21
README.md
21
README.md
@ -1,6 +1,12 @@
|
|||||||
<h1 align="center">
|
[Bilibili: 金羿ELS]: https://img.shields.io/badge/Bilibili-%E9%87%91%E7%BE%BFELS-00A1E7?style=for-the-badge
|
||||||
音·创 Musicreater
|
[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
|
||||||
</h1>
|
[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
|
||||||
|
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
|
||||||
|
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
|
||||||
|
|
||||||
|
|
||||||
|
<h1 align="center">音·创 Musicreater </h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="128" height="128" src="https://gitee.com/TriM-Organization/Musicreater/raw/master/resources/msctIcon.png">
|
<img width="128" height="128" src="https://gitee.com/TriM-Organization/Musicreater/raw/master/resources/msctIcon.png">
|
||||||
@ -92,9 +98,9 @@
|
|||||||
- <table><tr><td>感谢 **油炸**<QQ2836146704> 激励我们不断开发新的内容。</td><td><img height="50" src="https://foruda.gitee.com/images/1695478907647543027/08ea9909_9911226.jpeg"></td></tr></table>
|
- <table><tr><td>感谢 **油炸**<QQ2836146704> 激励我们不断开发新的内容。</td><td><img height="50" src="https://foruda.gitee.com/images/1695478907647543027/08ea9909_9911226.jpeg"></td></tr></table>
|
||||||
- 感谢 **雨**\<QQ237667809\> 反馈在新版本的指令格式下,计分板播放器的附加包无法播放的问题。
|
- 感谢 **雨**\<QQ237667809\> 反馈在新版本的指令格式下,计分板播放器的附加包无法播放的问题。
|
||||||
- 感谢 **梦幻duang**\<QQ13753593\> 为我们提供 Java 1.12.2 版本命令格式参考。
|
- 感谢 **梦幻duang**\<QQ13753593\> 为我们提供 Java 1.12.2 版本命令格式参考。
|
||||||
|
- 感谢 [_Open Note Block Studio_](https://github.com/OpenNBS/NoteBlockStudio) 项目的开发为我们提供持续的追赶动力。
|
||||||
|
|
||||||
> 感谢广大群友为此库提供的测试和建议等
|
> 感谢广大群友为此库提供的测试和建议等
|
||||||
>
|
|
||||||
> 若您对我们有所贡献但您的名字没有出现在此列表中,请联系我们!
|
> 若您对我们有所贡献但您的名字没有出现在此列表中,请联系我们!
|
||||||
|
|
||||||
## 联系 📞
|
## 联系 📞
|
||||||
@ -122,10 +128,3 @@ NOT AN OFFICIAL MINECRAFT PRODUCT.
|
|||||||
NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
|
NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
|
||||||
|
|
||||||
NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
|
NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
|
||||||
|
|
||||||
[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
|
|
||||||
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
|
|
||||||
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
|
|
||||||
|
16
README_EN.md
16
README_EN.md
@ -1,3 +1,10 @@
|
|||||||
|
[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
|
||||||
|
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
|
||||||
|
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
|
||||||
|
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
音·创 Musicreater
|
音·创 Musicreater
|
||||||
</h1>
|
</h1>
|
||||||
@ -91,9 +98,10 @@ This list is not in any order.
|
|||||||
- Thank _小埋_\<QQ2039310975\> for reporting the empty add-on packs title and description problem.
|
- Thank _小埋_\<QQ2039310975\> for reporting the empty add-on packs title and description problem.
|
||||||
- <table><tr><td>Thank <i>油炸</i> <QQ2836146704> for inspiring us to constantly develop something new.</td><td><img width="260" src="https://foruda.gitee.com/images/1695478907647543027/08ea9909_9911226.jpeg" alt="The groupmate on the picture was saying that our convert-QQ-bot had once brought him great convinience but now it closed down by some reason so he was feeling regretful." title=""It was once, a convert-QQ-bot is just in front my eyes" "Until lose, I finally know cannot chase back what I needs""></td><td><small>"It was once, a convert-QQ-bot is just in front my eyes"<br>"Until lose, I finally know cannot chase back what I needs"</small></td></tr></table>
|
- <table><tr><td>Thank <i>油炸</i> <QQ2836146704> for inspiring us to constantly develop something new.</td><td><img width="260" src="https://foruda.gitee.com/images/1695478907647543027/08ea9909_9911226.jpeg" alt="The groupmate on the picture was saying that our convert-QQ-bot had once brought him great convinience but now it closed down by some reason so he was feeling regretful." title=""It was once, a convert-QQ-bot is just in front my eyes" "Until lose, I finally know cannot chase back what I needs""></td><td><small>"It was once, a convert-QQ-bot is just in front my eyes"<br>"Until lose, I finally know cannot chase back what I needs"</small></td></tr></table>
|
||||||
- Thank _雨_\<QQ237667809\> for give us report that under the new `execute` command format that the scoreboard player's add-on packs cannot play correctly.
|
- Thank _雨_\<QQ237667809\> for give us report that under the new `execute` command format that the scoreboard player's add-on packs cannot play correctly.
|
||||||
|
- Thank _梦幻duang_\<QQ13753593\> for providing us with his knowlodeg of the command format in Minecraft: Java Edition Version 1.12.2.
|
||||||
|
- Thank [_Open Note Block Studio_](https://github.com/OpenNBS/NoteBlockStudio)'s Project for giving us the power and energy of continual developing.
|
||||||
|
|
||||||
> Thanks for the support and help of a lot of groupmates
|
> Thanks for the support and help of a lot of groupmates
|
||||||
>
|
|
||||||
> If you have given contributions but have not been in the list, please contact us!
|
> If you have given contributions but have not been in the list, please contact us!
|
||||||
|
|
||||||
## Contact Us 📞
|
## Contact Us 📞
|
||||||
@ -122,9 +130,3 @@ NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
|
|||||||
|
|
||||||
- 上文提及的 网易 公司,指代的是在中国大陆运营《我的世界:中国版》的上海网之易璀璨网络科技有限公司
|
- 上文提及的 网易 公司,指代的是在中国大陆运营《我的世界:中国版》的上海网之易璀璨网络科技有限公司
|
||||||
|
|
||||||
[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
|
|
||||||
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
|
|
||||||
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
|
|
||||||
|
@ -13,9 +13,7 @@ def main():
|
|||||||
if file.endswith(".egg-info"):
|
if file.endswith(".egg-info"):
|
||||||
egg_info.append(file)
|
egg_info.append(file)
|
||||||
console.print(file)
|
console.print(file)
|
||||||
for file in track(
|
for file in track(["build", "dist", "logs", *egg_info], description="正删档"):
|
||||||
["build", "dist", "logs", *egg_info], description="正删档"
|
|
||||||
):
|
|
||||||
if os.path.isdir(file) and os.access(file, os.W_OK):
|
if os.path.isdir(file) and os.access(file, os.W_OK):
|
||||||
shutil.rmtree(file)
|
shutil.rmtree(file)
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ ADD note_seq_2
|
|||||||
ADD XXH64(seq_2_note_count, 3)
|
ADD XXH64(seq_2_note_count, 3)
|
||||||
ADD XXH64(note_seq_2, seq_2_note_count)
|
ADD XXH64(note_seq_2, seq_2_note_count)
|
||||||
ADD XXH128(
|
ADD XXH128(
|
||||||
|
XOR(
|
||||||
XOR(
|
XOR(
|
||||||
XXH64(meta_info, note_count),
|
XXH64(meta_info, note_count),
|
||||||
XOR(
|
XOR(
|
||||||
@ -98,6 +99,11 @@ ADD XXH128(
|
|||||||
XXH64(note_seq_1, seq_1_note_count)
|
XXH64(note_seq_1, seq_1_note_count)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
XOR(
|
||||||
|
XXH64(seq_2_note_count, 3),
|
||||||
|
XXH64(note_seq_2, seq_2_note_count),
|
||||||
|
)
|
||||||
|
),
|
||||||
note_count
|
note_count
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
@ -1,14 +1,31 @@
|
|||||||
import Musicreater
|
import Musicreater
|
||||||
|
from Musicreater.utils import load_decode_msq_flush_release, load_decode_msq_metainfo
|
||||||
|
|
||||||
|
from rich.pretty import pprint
|
||||||
|
|
||||||
msc_seq = Musicreater.MusicSequence.from_mido(
|
msc_seq = Musicreater.MusicSequence.from_mido(
|
||||||
Musicreater.mido.MidiFile("./resources/测试片段.mid",),
|
Musicreater.mido.MidiFile(
|
||||||
|
"./resources/测试片段.mid",
|
||||||
|
),
|
||||||
"TEST-测试片段",
|
"TEST-测试片段",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pprint("音乐源取入成功:")
|
||||||
|
pprint(msc_seq)
|
||||||
|
|
||||||
with open("test.msq", "wb") as f:
|
with open("test.msq", "wb") as f:
|
||||||
f.write(msq_bytes := msc_seq.encode_dump())
|
f.write(msq_bytes := msc_seq.encode_dump())
|
||||||
|
|
||||||
with open("test.msq", "rb") as f:
|
with open("test.msq", "rb") as f:
|
||||||
msc_seq_r = Musicreater.MusicSequence.load_decode(f.read())
|
msc_seq_r = Musicreater.MusicSequence.load_decode(f.read())
|
||||||
|
|
||||||
print(msc_seq_r)
|
pprint("常规 MSQ 读取成功:")
|
||||||
|
pprint(msc_seq_r)
|
||||||
|
|
||||||
|
|
||||||
|
with open("test.msq", "rb") as f:
|
||||||
|
pprint("流式 MSQ 元数据:")
|
||||||
|
pprint(metas := load_decode_msq_metainfo(f))
|
||||||
|
pprint("流式 MSQ 音符序列:")
|
||||||
|
for i in load_decode_msq_flush_release(f, metas[-1], metas[-2]):
|
||||||
|
pprint(i)
|
||||||
|
@ -6,10 +6,6 @@ Copyright © 2025 Eilles & bgArray
|
|||||||
Terms & Conditions: License.md in the root directory
|
Terms & Conditions: License.md in the root directory
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
@ -130,6 +126,15 @@ print(
|
|||||||
input("midi路径:"),
|
input("midi路径:"),
|
||||||
play_speed=float(input("播放速度:")),
|
play_speed=float(input("播放速度:")),
|
||||||
old_exe_format=True,
|
old_exe_format=True,
|
||||||
|
note_table_replacement={
|
||||||
|
"note.iron_xylophone": "note.xylophone",
|
||||||
|
"note.cow_bell": "note.xylophone",
|
||||||
|
"note.didgeridoo": "note.guitar",
|
||||||
|
"note.bit": "note.harp",
|
||||||
|
"note.banjo": "note.flute",
|
||||||
|
"note.pling": "note.harp",
|
||||||
|
},
|
||||||
|
# pitched_note_table=Musicreater.MM_NBS_PITCHED_INSTRUMENT_TABLE,
|
||||||
),
|
),
|
||||||
input("输出路径:"),
|
input("输出路径:"),
|
||||||
Musicreater.experiment.ProgressBarStyle(),
|
Musicreater.experiment.ProgressBarStyle(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user