新增新文件路径小参数,新增音乐预览插件测试样例。修复小问题

This commit is contained in:
Eilles
2026-07-09 02:06:14 +08:00
parent 2c6e831533
commit fc9ec86adb
5 changed files with 88 additions and 30 deletions
+15
View File
@@ -17,10 +17,12 @@ Terms & Conditions: License.md in the root directory
from copy import deepcopy, copy from copy import deepcopy, copy
from pathlib import Path
from typing import Any, Dict, Generator, List, Optional, Tuple, Union, TypeVar from typing import Any, Dict, Generator, List, Optional, Tuple, Union, TypeVar
T = TypeVar("T") T = TypeVar("T")
def enumerated_stuffcopy_dictionary( def enumerated_stuffcopy_dictionary(
enumeration_times: int = 17, staff: T = {} enumeration_times: int = 17, staff: T = {}
) -> Dict[int, T]: ) -> Dict[int, T]:
@@ -30,3 +32,16 @@ def enumerated_stuffcopy_dictionary(
# 这告诉我们,你不能忽略任何一个复制的序列,因为它真的,我哭死,折磨我一整天,全在这个bug上了 # 这告诉我们,你不能忽略任何一个复制的序列,因为它真的,我哭死,折磨我一整天,全在这个bug上了
# 上面的这指的是 copy.deepcopy —— 金羿 来自 20260210 # 上面的这指的是 copy.deepcopy —— 金羿 来自 20260210
return {i: deepcopy(staff) for i in range(enumeration_times)} return {i: deepcopy(staff) for i in range(enumeration_times)}
def incremental_save_path(
file_name: str, suffix: str = ".file", appendix_connector: str = "-"
) -> Path:
ss_path = Path(file_name).with_suffix(suffix)
if ss_path.exists():
now_appendix = 2
while (
ss_path := Path(file_name + appendix_connector + str(now_appendix) + suffix)
).exists():
now_appendix += 1
return ss_path
@@ -107,6 +107,9 @@ class NoteDataConvert2PcmPlugin(MusicOutputPluginBase):
license="Apache 2.0", license="Apache 2.0",
) )
supported_formats = ("WAV", "WAVE", "PCM")
def dump(self, data: SingleMusic, file_path: Path, config: PcmConversionConfig): def dump(self, data: SingleMusic, file_path: Path, config: PcmConversionConfig):
pr = perf_counter_ns() pr = perf_counter_ns()
@@ -48,7 +48,7 @@ from Musicreater.constants import MM_INSTRUMENT_DEVIATION_TABLE
class MusicPreview: class MusicPreview:
# 当前的资源存储方法过于鸡肋 # 当前的资源存储方法过于鸡肋
# 应当依托于 SingleMusic 和 SingleTrack 提供的 extra_info 参数,得到更优的解法 # 应当依托于 SingleMusic 和 SingleTrack 提供的 extra_info 参数,得到更优的解法
# 或者更理想的情况是把当前插件作为一个 Service 插件,然后通过 serve API 进行调用 # 或者更理想的情况是把当前插件作为一个 Service 插件,然后通过 serve API 进行调用
@@ -102,12 +102,11 @@ class MusicPreview:
self.output_sample_rate = sample_rate self.output_sample_rate = sample_rate
self.get_value_method = value_get_method self.get_value_method = value_get_method
self.resources_path = resource_folder self.resources_path = resource_folder
# 在当前算法下,小数点精度必须为 0 # 在当前算法下,小数点精度必须为 0
# 此处 TODO,需待旧梦来完善 # 此处 TODO,需待旧梦来完善
self.pitch_precision_decimals = 0 self.pitch_precision_decimals = 0
self.pitch_deviation = music_deviation self.pitch_deviation = music_deviation
for file in self.resources_path.iterdir(): for file in self.resources_path.iterdir():
@@ -189,13 +188,13 @@ class MusicPreview:
else: else:
# if self.mode == 1: # if self.mode == 1:
# 重采样, 不变调 # 重采样, 不变调
print(">>", sound_name, pitch) # print(">>", sound_name, pitch)
self.res_data[sound_name][pitch] = librosa.resample( self.res_data[sound_name][pitch] = librosa.resample(
y_orig, y_orig,
orig_sr=sr_orig, orig_sr=sr_orig,
target_sr=self.output_sample_rate, target_sr=self.output_sample_rate,
fix=False, # 尽管这样不变调,但是也不应将 pitch 与打击乐器联系在一起 fix=False, # 尽管这样不变调,但是也不应将 pitch 与打击乐器联系在一起
) ) # 已经在下面重新用 0 取代了打击乐器的 pitch
"""elif self.mode == 0: """elif self.mode == 0:
# 重采样, 不变调, 衰弱 # 重采样, 不变调, 衰弱
self.cache_dict[raw_name] = librosa_resample( self.cache_dict[raw_name] = librosa_resample(
@@ -221,14 +220,15 @@ class MusicPreview:
duration: int, duration: int,
): ):
print( # print(
sound_name, # sound_name,
pitch, # pitch,
">>", # ">>",
(pitch := self.make_pitch_accurate(pitch)), # (pitch := self.make_pitch_accurate(pitch)),
percussive, # percussive,
duration, # duration,
) # )
pitch = 0 if percussive else self.make_pitch_accurate(pitch)
if sound_name in self.res_data: if sound_name in self.res_data:
if pitch in self.res_data[sound_name]: if pitch in self.res_data[sound_name]:
@@ -333,24 +333,24 @@ class MusicPreview:
out_sr = self.output_sample_rate out_sr = self.output_sample_rate
for note in music.get_minenotes(start_time=start_tick, end_time=end_tick): for note in music.get_minenotes(start_time=start_tick, end_time=end_tick):
accurate_pitch = self.make_pitch_accurate( accurate_pitch = (
note.pitch 0
- 60 if note.percussive
- ( else self.make_pitch_accurate(
0 note.pitch
if note.percussive - 60
else MM_INSTRUMENT_DEVIATION_TABLE.get(note.instrument, 6) - MM_INSTRUMENT_DEVIATION_TABLE.get(note.instrument, 6)
) )
) )
print( # print(
":", # ":",
note.instrument, # note.instrument,
note.pitch, # note.pitch,
">>", # ">>",
accurate_pitch, # accurate_pitch,
note.percussive, # note.percussive,
note.duration_tick, # note.duration_tick,
) # )
if not note.percussive: if not note.percussive:
overlay( overlay(
self.res_data[note.instrument][accurate_pitch] self.res_data[note.instrument][accurate_pitch]
+1 -1
View File
@@ -509,7 +509,7 @@ class SingleTrack(List[SingleNote]):
self.argument_curves = {item: None for item in CurvableParam} self.argument_curves = {item: None for item in CurvableParam}
super().__init__(*args) super().__init__(args)
super().sort() super().sort()
@classmethod @classmethod
+40
View File
@@ -0,0 +1,40 @@
# 一个简单的项目实践测试
from pathlib import Path
from rich import print
from Musicreater import load_plugin_from_module, MusiCreater
from Musicreater.plugins import _global_plugin_registry
from Musicreater._utils import incremental_save_path
load_plugin_from_module("Musicreater.builtin_plugins.midi_read")
load_plugin_from_module("Musicreater.builtin_plugins.music_preview")
from Musicreater.builtin_plugins.midi_read import MidiImportConfig
from Musicreater.builtin_plugins.music_preview import PcmConversionConfig
print("当前支持的导入格式:", _global_plugin_registry.supported_input_formats())
print("当前支持的导出格式:", _global_plugin_registry.supported_output_formats())
msct = MusiCreater.import_music(
Path(input("文件路径:")).resolve(),
plugin_config=MidiImportConfig(),
)
print("全局插件注册表:", _global_plugin_registry)
print("插件缓存字典:", msct._plugin_cache)
print(
msct.export_music(
(fn := incremental_save_path("output", suffix=".wav")),
plugin_id="music_to_pcm_plugin",
plugin_config=PcmConversionConfig(
assets_path=Path("./vanilla_assets/wav/").resolve(),
synthesis_mode=2,
pitch_accuracy_decimals=0,
),
),
"\n文件路径:",
fn,
)