mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2024-11-11 01:27:35 +08:00
新的转换算法测试,更好的声音适配
This commit is contained in:
parent
0b0328bc44
commit
fc138f1dbf
@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
|
||||
__version__ = "1.6.1"
|
||||
__vername__ = "更新乐器对照表"
|
||||
__version__ = "1.6.2"
|
||||
__vername__ = "新的转换算法测试,更好的声音适配"
|
||||
__author__ = (
|
||||
("金羿", "Eilles Wan"),
|
||||
("诸葛亮与八卦阵", "bgArray"),
|
||||
|
@ -25,6 +25,7 @@ from .subclass import *
|
||||
from .utils import *
|
||||
from .types import Tuple, List, Dict
|
||||
|
||||
|
||||
class FutureMidiConvertRSNB(MidiConvert):
|
||||
"""
|
||||
加入红石音乐适配
|
||||
@ -57,101 +58,6 @@ class FutureMidiConvertRSNB(MidiConvert):
|
||||
except KeyError:
|
||||
return "air"
|
||||
|
||||
def to_note_list_in_delay(
|
||||
self,
|
||||
) -> Tuple[Dict[int, SingleNoteBox], int]:
|
||||
"""
|
||||
使用金羿的转换思路,将midi转换为我的世界音符盒音高、乐器及延迟列表,并输出每个音符之后的延迟
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple( Dict[int, SingleNoteBox], int音乐时长游戏刻 )
|
||||
"""
|
||||
|
||||
self.to_music_channels()
|
||||
|
||||
tracks = {}
|
||||
note_range = {}
|
||||
InstID = -1
|
||||
# cmd_amount = 0
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
for i in self.channels.keys():
|
||||
# 如果当前通道为空 则跳过
|
||||
if not self.channels[i]:
|
||||
continue
|
||||
|
||||
# 第十通道是打击乐通道
|
||||
SpecialBits = True if i == 9 else False
|
||||
|
||||
for track_no, track in self.channels[i].items():
|
||||
for msg in track:
|
||||
if msg[0] == "PgmC":
|
||||
InstID = msg[1]
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
# block_id = self.soundID_to_block((
|
||||
# self.perc_inst_to_soundID_withX(msg[1])
|
||||
# if SpecialBits
|
||||
# else self.inst_to_souldID_withX(InstID)
|
||||
# )[0])
|
||||
|
||||
# delaytime_now = round(msg[-1] / 50)
|
||||
|
||||
note_ = 2 ** ((msg[1] - 60) / 12)
|
||||
|
||||
try:
|
||||
tracks[msg[-1]].append(
|
||||
(
|
||||
InstID,
|
||||
note_,
|
||||
)
|
||||
)
|
||||
except KeyError:
|
||||
tracks[msg[-1]] = [(InstID, note_)]
|
||||
|
||||
try:
|
||||
note_range[InstID]["max"] = max(
|
||||
note_range[InstID]["max"], note_
|
||||
)
|
||||
note_range[InstID]["min"] = min(
|
||||
note_range[InstID]["min"], note_
|
||||
)
|
||||
except KeyError:
|
||||
note_range[InstID] = {"max": note_, "min": note_}
|
||||
|
||||
del InstID
|
||||
all_ticks = list(tracks.keys())
|
||||
all_ticks.sort()
|
||||
results = []
|
||||
print(note_range)
|
||||
|
||||
exit()
|
||||
|
||||
for i in range(len(all_ticks)):
|
||||
for j in range(len(tracks[all_ticks[i]])):
|
||||
results.append(
|
||||
SingleCommand(
|
||||
tracks[all_ticks[i]][j],
|
||||
tick_delay=(
|
||||
0
|
||||
if j != 0
|
||||
else (
|
||||
all_ticks[i] - all_ticks[i - 1]
|
||||
if i != 0
|
||||
else all_ticks[i]
|
||||
)
|
||||
),
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(i), max_volume * 100, ""
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
self.music_command_list = results
|
||||
self.music_tick_num = max(all_ticks)
|
||||
return results, self.music_tick_num
|
||||
|
||||
|
||||
class FutureMidiConvertM4(MidiConvert):
|
||||
"""
|
||||
@ -163,172 +69,50 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
@staticmethod
|
||||
def _linear_note(
|
||||
_note: SingleNote,
|
||||
_apply_time_division: int = 100,
|
||||
) -> List[Tuple[int, int, int, int, float],]:
|
||||
_apply_time_division: float = 100,
|
||||
) -> List[SingleNote]:
|
||||
"""传入音符数据,返回以半秒为分割的插值列表
|
||||
:param _note: SingleNote 音符
|
||||
:param _apply_time_division: int 间隔毫秒数
|
||||
:return list[tuple(int开始时间(毫秒), int乐器, int音符, int力度(内置), float音量(播放)),]"""
|
||||
|
||||
if _note.percussive:
|
||||
return [
|
||||
_note,
|
||||
]
|
||||
|
||||
totalCount = int(_note.duration / _apply_time_division)
|
||||
|
||||
if totalCount == 0:
|
||||
return [
|
||||
(_note.start_time, _note.inst, _note.pitch, _note.velocity, 1),
|
||||
_note,
|
||||
]
|
||||
# print(totalCount)
|
||||
|
||||
result: List[Tuple[int, int, int, int, float],] = []
|
||||
result: List[SingleNote] = []
|
||||
|
||||
for _i in range(totalCount):
|
||||
result.append(
|
||||
(
|
||||
_note.start_time + _i * _apply_time_division,
|
||||
_note.instrument,
|
||||
_note.pitch,
|
||||
_note.velocity,
|
||||
((totalCount - _i) / totalCount),
|
||||
SingleNote(
|
||||
instrument=_note.inst,
|
||||
pitch=_note.pitch,
|
||||
velocity=_note.velocity,
|
||||
startime=int(_note.start_time + _i * (_note.duration / totalCount)),
|
||||
lastime=int(_note.duration / totalCount),
|
||||
track_number=_note.track_no,
|
||||
is_percussion=_note.percussive,
|
||||
)
|
||||
# (
|
||||
# _note.start_time + _i * _apply_time_division,
|
||||
# _note.instrument,
|
||||
# _note.pitch,
|
||||
# _note.velocity,
|
||||
# ((totalCount - _i) / totalCount),
|
||||
# )
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
# 简单的单音填充
|
||||
def to_command_list_in_score(
|
||||
self,
|
||||
scoreboard_name: str = "mscplay",
|
||||
max_volume: float = 1.0,
|
||||
speed: float = 1.0,
|
||||
) -> Tuple[List[List[SingleCommand]], int, int]:
|
||||
"""
|
||||
使用金羿的转换思路,使用完全填充算法优化音感后,将midi转换为我的世界命令列表
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scoreboard_name: str
|
||||
我的世界的计分板名称
|
||||
max_volume: float
|
||||
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放
|
||||
speed: float
|
||||
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple( list[list[SingleCommand指令,... ],... ], int指令数量, int音乐时长游戏刻 )
|
||||
"""
|
||||
|
||||
if speed == 0:
|
||||
raise ZeroSpeedError("播放速度仅可为正实数")
|
||||
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
|
||||
|
||||
self.to_music_channels()
|
||||
|
||||
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
|
||||
InstID = -1
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
for i in self.channels.keys():
|
||||
# 如果当前通道为空 则跳过
|
||||
if not self.channels[i]:
|
||||
continue
|
||||
|
||||
# nowChannel = []
|
||||
for track_no, track in self.channels[i].items():
|
||||
noteMsgs = []
|
||||
MsgIndex = []
|
||||
|
||||
for msg in track:
|
||||
if msg[0] == "PgmC":
|
||||
InstID = msg[1]
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
noteMsgs.append(msg[1:])
|
||||
MsgIndex.append(msg[1])
|
||||
|
||||
elif msg[0] == "NoteE":
|
||||
if msg[1] in MsgIndex:
|
||||
note_channels[i].append(
|
||||
SingleNote(
|
||||
InstID,
|
||||
msg[1],
|
||||
noteMsgs[MsgIndex.index(msg[1])][1],
|
||||
noteMsgs[MsgIndex.index(msg[1])][2],
|
||||
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
|
||||
track_number=track_no,
|
||||
)
|
||||
)
|
||||
noteMsgs.pop(MsgIndex.index(msg[1]))
|
||||
MsgIndex.pop(MsgIndex.index(msg[1]))
|
||||
|
||||
del InstID
|
||||
|
||||
tracks = []
|
||||
cmd_amount = 0
|
||||
max_score = 0
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
for no, track in note_channels.items():
|
||||
# 如果当前通道为空 则跳过
|
||||
if not track:
|
||||
continue
|
||||
|
||||
SpecialBits = True if no == 9 else False
|
||||
|
||||
track_now = []
|
||||
|
||||
for note in track:
|
||||
for every_note in self._linear_note(
|
||||
note, 100 if note.track_no == 0 else 500
|
||||
):
|
||||
soundID, _X = (
|
||||
self.perc_inst_to_soundID_withX(note.pitch)
|
||||
if SpecialBits
|
||||
else self.inst_to_souldID_withX(note.inst)
|
||||
)
|
||||
|
||||
score_now = round(every_note[0] / speed / 50)
|
||||
|
||||
max_score = max(max_score, score_now)
|
||||
mc_pitch = 2 ** ((note.pitch - 60 - _X) / 12)
|
||||
blockmeter = (
|
||||
1
|
||||
/ (1 if note.track_no == 0 else 0.9)
|
||||
/ max_volume
|
||||
/ every_note[4]
|
||||
- 1
|
||||
)
|
||||
|
||||
track_now.append(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(
|
||||
"@a[scores=({}={})]".format(scoreboard_name, score_now)
|
||||
.replace("(", r"{")
|
||||
.replace(")", r"}")
|
||||
)
|
||||
+ "playsound {} @s ^ ^ ^{} {} {}".format(
|
||||
soundID,
|
||||
blockmeter,
|
||||
note.velocity / 128,
|
||||
"" if SpecialBits else mc_pitch,
|
||||
),
|
||||
annotation="在{}播放{}%({}BM)的{}音".format(
|
||||
mctick2timestr(score_now),
|
||||
max_volume * 100,
|
||||
blockmeter,
|
||||
"{}:{}".format(soundID, note.pitch),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
cmd_amount += 1
|
||||
|
||||
if track_now:
|
||||
self.music_command_list.extend(track_now)
|
||||
tracks.append(track_now)
|
||||
|
||||
self.music_tick_num = max_score
|
||||
return (tracks, cmd_amount, max_score)
|
||||
|
||||
# 简单的单音填充的延迟应用
|
||||
def to_command_list_in_delay(
|
||||
self,
|
||||
max_volume: float = 1.0,
|
||||
@ -336,7 +120,7 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
player_selector: str = "@a",
|
||||
) -> Tuple[List[SingleCommand], int, int]:
|
||||
"""
|
||||
使用金羿的转换思路,使用完全填充算法优化音感后,将midi转换为我的世界命令列表,并输出每个音符之后的延迟
|
||||
将midi转换为我的世界命令列表,并输出每个音符之后的延迟
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -353,130 +137,48 @@ class FutureMidiConvertM4(MidiConvert):
|
||||
"""
|
||||
|
||||
if speed == 0:
|
||||
raise ZeroSpeedError("播放速度仅可为正实数")
|
||||
raise ZeroSpeedError("播放速度仅可为(0,1]范围内的正实数")
|
||||
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
|
||||
|
||||
self.to_music_channels()
|
||||
|
||||
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
|
||||
InstID = -1
|
||||
notes_list: List[SingleNote] = []
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
for i in self.channels.keys():
|
||||
# 如果当前通道为空 则跳过
|
||||
if not self.channels[i]:
|
||||
continue
|
||||
|
||||
# nowChannel = []
|
||||
for track_no, track in self.channels[i].items():
|
||||
noteMsgs = []
|
||||
MsgIndex = []
|
||||
|
||||
for msg in track:
|
||||
if msg[0] == "PgmC":
|
||||
InstID = msg[1]
|
||||
|
||||
elif msg[0] == "NoteS":
|
||||
noteMsgs.append(msg[1:])
|
||||
MsgIndex.append(msg[1])
|
||||
|
||||
elif msg[0] == "NoteE":
|
||||
if msg[1] in MsgIndex:
|
||||
note_channels[i].append(
|
||||
SingleNote(
|
||||
InstID,
|
||||
msg[1],
|
||||
noteMsgs[MsgIndex.index(msg[1])][1],
|
||||
noteMsgs[MsgIndex.index(msg[1])][2],
|
||||
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
|
||||
track_number=track_no,
|
||||
)
|
||||
)
|
||||
noteMsgs.pop(MsgIndex.index(msg[1]))
|
||||
MsgIndex.pop(MsgIndex.index(msg[1]))
|
||||
|
||||
del InstID
|
||||
|
||||
tracks = {}
|
||||
InstID = -1
|
||||
# open("RES.TXT", "w", encoding="utf-8").write(str(note_channels))
|
||||
|
||||
# 此处 我们把通道视为音轨
|
||||
for no, track in note_channels.items():
|
||||
# 如果当前通道为空 则跳过
|
||||
if not track:
|
||||
continue
|
||||
|
||||
SpecialBits = True if no == 9 else False
|
||||
|
||||
for note in track:
|
||||
liner_list = self._linear_note(note, 100 if note.track_no == 0 else 500)
|
||||
for every_note in liner_list:
|
||||
soundID, _X = (
|
||||
self.perc_inst_to_soundID_withX(note.pitch)
|
||||
if SpecialBits
|
||||
else self.inst_to_souldID_withX(note.inst)
|
||||
)
|
||||
|
||||
score_now = round(every_note[0] / speed / 50)
|
||||
|
||||
try:
|
||||
tracks[score_now].append(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
|
||||
+ (
|
||||
""
|
||||
if SpecialBits
|
||||
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
|
||||
)
|
||||
)
|
||||
except KeyError:
|
||||
tracks[score_now] = [
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
|
||||
+ (
|
||||
""
|
||||
if SpecialBits
|
||||
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
|
||||
)
|
||||
]
|
||||
|
||||
all_ticks = list(tracks.keys())
|
||||
all_ticks.sort()
|
||||
results: List[SingleCommand] = []
|
||||
max_multi = 0
|
||||
now_multi_delay = 0
|
||||
now_multi = 0
|
||||
|
||||
for i in range(len(all_ticks)):
|
||||
l = len(tracks[all_ticks[i]])
|
||||
for j in range(l):
|
||||
results.append(
|
||||
SingleCommand(
|
||||
tracks[all_ticks[i]][j],
|
||||
tick_delay=(
|
||||
0
|
||||
if j != 0
|
||||
else (
|
||||
all_ticks[i] - all_ticks[i - 1]
|
||||
if i != 0
|
||||
else all_ticks[i]
|
||||
)
|
||||
),
|
||||
annotation="由 音·创 生成",
|
||||
)
|
||||
)
|
||||
if results[-1].delay + now_multi_delay <= 1:
|
||||
now_multi += 1
|
||||
now_multi_delay += results[-1].delay
|
||||
for channel in self.to_music_note_channels().values():
|
||||
for note in channel:
|
||||
if not note.percussive:
|
||||
notes_list.extend(self._linear_note(note, note.get_mc_pitch * 500))
|
||||
else:
|
||||
max_multi = max(max_multi, now_multi)
|
||||
now_multi = 0
|
||||
now_multi_delay = 0
|
||||
notes_list.append(note)
|
||||
|
||||
self.music_command_list = results
|
||||
self.music_tick_num = max(all_ticks)
|
||||
return results, self.music_tick_num, max_multi
|
||||
notes_list.sort(key=lambda a: a.start_time)
|
||||
|
||||
self.music_command_list = []
|
||||
multi = max_multi = 0
|
||||
delaytime_previous = 0
|
||||
|
||||
for note in notes_list:
|
||||
delaytime_now = round(note.start_time / speed / 50)
|
||||
if (tickdelay := (delaytime_now - delaytime_previous)) == 0:
|
||||
multi += 1
|
||||
else:
|
||||
max_multi = max(max_multi, multi)
|
||||
multi = 0
|
||||
self.music_command_list.append(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ note.to_command(max_volume),
|
||||
tick_delay=tickdelay,
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(delaytime_now),
|
||||
max_volume * 100,
|
||||
"{}:{}".format(note.mc_sound_ID, note.mc_pitch),
|
||||
),
|
||||
)
|
||||
)
|
||||
delaytime_previous = delaytime_now
|
||||
|
||||
self.music_tick_num = round(notes_list[-1].start_time / speed / 50)
|
||||
return self.music_command_list, self.music_tick_num, max_multi + 1
|
||||
|
||||
|
||||
class FutureMidiConvertM5(MidiConvert):
|
||||
|
@ -631,7 +631,9 @@ class MidiConvert:
|
||||
.replace("(", r"{")
|
||||
.replace(")", r"}")
|
||||
)
|
||||
+ note.to_command(max_volume),
|
||||
+ note.to_command(
|
||||
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
|
||||
),
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(score_now),
|
||||
max_volume * 100,
|
||||
@ -698,7 +700,9 @@ class MidiConvert:
|
||||
self.music_command_list.append(
|
||||
SingleCommand(
|
||||
self.execute_cmd_head.format(player_selector)
|
||||
+ note.to_command(max_volume),
|
||||
+ note.to_command(
|
||||
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
|
||||
),
|
||||
tick_delay=tickdelay,
|
||||
annotation="在{}播放{}%的{}音".format(
|
||||
mctick2timestr(delaytime_now),
|
||||
|
@ -21,7 +21,7 @@ from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from .constants import PERCUSSION_INSTRUMENT_LIST
|
||||
from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX
|
||||
from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX, volume2distance
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
@ -78,8 +78,6 @@ class SingleNote:
|
||||
"""音符持续时间 ms"""
|
||||
self.track_no: int = track_number
|
||||
"""音符所处的音轨"""
|
||||
self.track_no: int = track_number
|
||||
"""音符所处的音轨"""
|
||||
|
||||
self.percussive = (
|
||||
(is_percussion in PERCUSSION_INSTRUMENT_LIST)
|
||||
@ -89,31 +87,48 @@ class SingleNote:
|
||||
"""是否为打击乐器"""
|
||||
|
||||
@property
|
||||
def inst(self):
|
||||
def inst(self) -> int:
|
||||
"""乐器编号"""
|
||||
return self.instrument
|
||||
|
||||
@inst.setter
|
||||
def inst(self, inst_):
|
||||
def inst(self, inst_: int):
|
||||
self.instrument = inst_
|
||||
|
||||
@property
|
||||
def pitch(self):
|
||||
def pitch(self) -> int:
|
||||
"""音符编号"""
|
||||
return self.note
|
||||
|
||||
def __str__(self):
|
||||
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {},)".format(
|
||||
@property
|
||||
def get_mc_pitch(self) -> float:
|
||||
self.mc_sound_ID, _X = (
|
||||
perc_inst_to_soundID_withX(self.inst)
|
||||
if self.percussive
|
||||
else inst_to_souldID_withX(self.inst)
|
||||
)
|
||||
return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
|
||||
|
||||
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.percussive,
|
||||
self.inst,
|
||||
self.velocity,
|
||||
self.start_time,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
)
|
||||
if self.percussive
|
||||
else (
|
||||
self.percussive,
|
||||
@ -122,6 +137,7 @@ class SingleNote:
|
||||
self.velocity,
|
||||
self.start_time,
|
||||
self.duration,
|
||||
self.track_no,
|
||||
)
|
||||
)
|
||||
|
||||
@ -133,6 +149,7 @@ class SingleNote:
|
||||
"Velocity": self.velocity,
|
||||
"StartTime": self.start_time,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
}
|
||||
if self.percussive
|
||||
else {
|
||||
@ -142,6 +159,7 @@ class SingleNote:
|
||||
"Velocity": self.velocity,
|
||||
"StartTime": self.start_time,
|
||||
"Duration": self.duration,
|
||||
"Track": self.track_no,
|
||||
}
|
||||
)
|
||||
|
||||
@ -165,14 +183,13 @@ class SingleNote:
|
||||
|
||||
# delaytime_now = round(self.start_time / float(speed) / 50)
|
||||
self.mc_pitch = "" if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
|
||||
self.mc_distance_volume = 128 / volume_percentage / self.velocity + (
|
||||
1 if self.percussive else self.velocity / 32
|
||||
)
|
||||
|
||||
self.mc_distance_volume = volume2distance(self.velocity * volume_percentage)
|
||||
|
||||
return "playsound {} @s ^ ^ ^{} {} {}".format(
|
||||
self.mc_sound_ID,
|
||||
self.mc_distance_volume,
|
||||
self.velocity / 128,
|
||||
volume_percentage,
|
||||
self.mc_pitch,
|
||||
)
|
||||
|
||||
|
@ -58,7 +58,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],]],],]
|
||||
"""
|
||||
|
@ -15,6 +15,8 @@ Terms & Conditions: License.md in the root directory
|
||||
# Email TriM-Organization@hotmail.com
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
import math
|
||||
|
||||
from .constants import PERCUSSION_INSTRUMENT_TABLE, PITCHED_INSTRUMENT_TABLE
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
@ -89,3 +91,29 @@ def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]:
|
||||
|
||||
# 明明已经走了
|
||||
# 凭什么还要在我心里留下缠绵缱绻
|
||||
|
||||
|
||||
def volume2distance(vol: float) -> float:
|
||||
"""
|
||||
midi力度值拟合成的距离函数
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vol: int
|
||||
midi音符力度值
|
||||
|
||||
Returns
|
||||
-------
|
||||
float播放中心到玩家的距离
|
||||
"""
|
||||
return (
|
||||
-8.081720684086314
|
||||
* math.log(
|
||||
vol + 14.579508825070013,
|
||||
)
|
||||
+ 37.65806375944386
|
||||
if vol < 60.64
|
||||
else 0.2721359356095803 * ((vol + 2592.272889454798) ** 1.358571233418649)
|
||||
+ -6.313841334963396 * (vol + 2592.272889454798)
|
||||
+ 4558.496367823575
|
||||
)
|
||||
|
@ -1,13 +1,13 @@
|
||||
import Musicreater.experiment
|
||||
import Musicreater.plugin
|
||||
import Musicreater.plugin.addonpack
|
||||
import Musicreater.plugin.mcstructfile
|
||||
|
||||
print(
|
||||
Musicreater.plugin.addonpack.to_addon_pack_in_delay(
|
||||
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(input("midi路径:"), old_exe_format=False),
|
||||
Musicreater.plugin.ConvertConfig(
|
||||
input("输出路径:"),
|
||||
volume=1
|
||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
|
||||
input("midi路径:"), old_exe_format=False
|
||||
),
|
||||
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
|
||||
max_height=32,
|
||||
)
|
||||
)
|
||||
|
@ -6,5 +6,6 @@ print(
|
||||
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
|
||||
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
|
||||
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
|
||||
max_height=32,
|
||||
)
|
||||
)
|
||||
|
42
resources/test/volumn_function_fit.py
Normal file
42
resources/test/volumn_function_fit.py
Normal file
@ -0,0 +1,42 @@
|
||||
import numpy as np
|
||||
from scipy.optimize import curve_fit
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def q_function1(x, a, a2, c1,):
|
||||
return a * np.log( x + a2,)+ c1
|
||||
|
||||
def q_function2(x, b, b2, b3, b4, c2):
|
||||
return b * ((x + b2) ** b3) + b4 * (x+b2) + c2
|
||||
|
||||
|
||||
x_data = np.array([0, 16, 32, 48, 64, 80, 96, 112, 128])
|
||||
y_data = np.array([16, 10, 6.75, 4, 2.5, 1.6, 0.8, 0.3, 0])
|
||||
|
||||
|
||||
p_est1, err_est1 = curve_fit(q_function1, x_data[:5], y_data[:5], maxfev=1000000)
|
||||
p_est2, err_est2 = curve_fit(q_function2, x_data[4:], y_data[4:], maxfev=1000000)
|
||||
|
||||
|
||||
print(q_function1(x_data[:5], *p_est1))
|
||||
print(q_function2(x_data[4:], *p_est2))
|
||||
|
||||
print("参数一:",*p_est1)
|
||||
print("参数二:",*p_est2)
|
||||
|
||||
# 绘制图像
|
||||
plt.plot(
|
||||
np.arange(0, 64.1, 0.1), q_function1(np.arange(0, 64.1, 0.1), *p_est1), label=r"FIT1"
|
||||
)
|
||||
plt.plot(
|
||||
np.arange(64, 128.1, 0.1), q_function2(np.arange(64, 128.1, 0.1), *p_est2), label=r"FIT2"
|
||||
)
|
||||
|
||||
|
||||
plt.scatter(x_data, y_data, color="red") # 标记给定的点
|
||||
# plt.xlabel('x')
|
||||
# plt.ylabel('y')
|
||||
plt.title("Function Fit")
|
||||
plt.legend()
|
||||
# plt.grid(True)
|
||||
plt.show()
|
36
resources/test/volumn_function_test.py
Normal file
36
resources/test/volumn_function_test.py
Normal file
@ -0,0 +1,36 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
# 定义对数函数
|
||||
def q_function1(vol):
|
||||
# return -23.65060754864053*((x+508.2130392724084)**0.8433764630986903) + 7.257078620637543 * (x+407.86870598508153) + 1585.6201108739122
|
||||
# return -58.863374003875954 *((x+12.41481943150274 )**0.9973316187745871 ) +57.92341268595151 * (x+ 13.391132186222036) + -32.92986286030519
|
||||
return -8.081720684086314 * np.log( vol + 14.579508825070013,)+ 37.65806375944386
|
||||
|
||||
|
||||
def q_function2(vol):
|
||||
return 0.2721359356095803 * ((vol + 2592.272889454798) ** 1.358571233418649) + -6.313841334963396 * (vol + 2592.272889454798) + 4558.496367823575
|
||||
|
||||
# 生成 x 值
|
||||
x_values = np.linspace(0, 128, 1000)
|
||||
|
||||
|
||||
x_data = np.array([0,16,32,48,64,80,96,112,128])
|
||||
y_data = np.array([16, 10, 6.75, 4, 2.5, 1.6, 0.8, 0.3, 0])
|
||||
|
||||
|
||||
print(q_function1(x_data))
|
||||
print(q_function2(x_data))
|
||||
|
||||
# 绘制图像
|
||||
plt.plot(x_values, q_function1(x_values,),label = "fit1")
|
||||
plt.plot(x_values, q_function2(x_values,),label = "fit2")
|
||||
plt.scatter(x_data, y_data, color='red') # 标记给定的点
|
||||
# plt.scatter(x_data, y_data2, color='green') # 标记给定的点
|
||||
# plt.scatter(x_data, y_data3, color='blue') # 标记给定的点
|
||||
plt.xlabel('x')
|
||||
plt.ylabel('y')
|
||||
plt.title('Function')
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.show()
|
Loading…
Reference in New Issue
Block a user