diff --git a/Musicreater/_utils.py b/Musicreater/_utils.py index 317f1dc..ef1ba05 100644 --- a/Musicreater/_utils.py +++ b/Musicreater/_utils.py @@ -17,10 +17,12 @@ Terms & Conditions: License.md in the root directory from copy import deepcopy, copy +from pathlib import Path from typing import Any, Dict, Generator, List, Optional, Tuple, Union, TypeVar T = TypeVar("T") + def enumerated_stuffcopy_dictionary( enumeration_times: int = 17, staff: T = {} ) -> Dict[int, T]: @@ -30,3 +32,16 @@ def enumerated_stuffcopy_dictionary( # 这告诉我们,你不能忽略任何一个复制的序列,因为它真的,我哭死,折磨我一整天,全在这个bug上了 # 上面的这指的是 copy.deepcopy —— 金羿 来自 20260210 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 diff --git a/Musicreater/builtin_plugins/music_preview/__init__.py b/Musicreater/builtin_plugins/music_preview/__init__.py index f2787b2..498976f 100644 --- a/Musicreater/builtin_plugins/music_preview/__init__.py +++ b/Musicreater/builtin_plugins/music_preview/__init__.py @@ -107,6 +107,9 @@ class NoteDataConvert2PcmPlugin(MusicOutputPluginBase): license="Apache 2.0", ) + + supported_formats = ("WAV", "WAVE", "PCM") + def dump(self, data: SingleMusic, file_path: Path, config: PcmConversionConfig): pr = perf_counter_ns() diff --git a/Musicreater/builtin_plugins/music_preview/main.py b/Musicreater/builtin_plugins/music_preview/main.py index 54e6a0a..4167a77 100644 --- a/Musicreater/builtin_plugins/music_preview/main.py +++ b/Musicreater/builtin_plugins/music_preview/main.py @@ -48,7 +48,7 @@ from Musicreater.constants import MM_INSTRUMENT_DEVIATION_TABLE class MusicPreview: - + # 当前的资源存储方法过于鸡肋 # 应当依托于 SingleMusic 和 SingleTrack 提供的 extra_info 参数,得到更优的解法 # 或者更理想的情况是把当前插件作为一个 Service 插件,然后通过 serve API 进行调用 @@ -102,12 +102,11 @@ class MusicPreview: self.output_sample_rate = sample_rate self.get_value_method = value_get_method self.resources_path = resource_folder - + # 在当前算法下,小数点精度必须为 0 # 此处 TODO,需待旧梦来完善 self.pitch_precision_decimals = 0 - self.pitch_deviation = music_deviation for file in self.resources_path.iterdir(): @@ -189,13 +188,13 @@ class MusicPreview: else: # if self.mode == 1: # 重采样, 不变调 - print(">>", sound_name, pitch) + # print(">>", sound_name, pitch) self.res_data[sound_name][pitch] = librosa.resample( y_orig, orig_sr=sr_orig, target_sr=self.output_sample_rate, fix=False, # 尽管这样不变调,但是也不应将 pitch 与打击乐器联系在一起 - ) + ) # 已经在下面重新用 0 取代了打击乐器的 pitch """elif self.mode == 0: # 重采样, 不变调, 衰弱 self.cache_dict[raw_name] = librosa_resample( @@ -221,14 +220,15 @@ class MusicPreview: duration: int, ): - print( - sound_name, - pitch, - ">>", - (pitch := self.make_pitch_accurate(pitch)), - percussive, - duration, - ) + # print( + # sound_name, + # pitch, + # ">>", + # (pitch := self.make_pitch_accurate(pitch)), + # percussive, + # duration, + # ) + pitch = 0 if percussive else self.make_pitch_accurate(pitch) if sound_name in self.res_data: if pitch in self.res_data[sound_name]: @@ -333,24 +333,24 @@ class MusicPreview: out_sr = self.output_sample_rate for note in music.get_minenotes(start_time=start_tick, end_time=end_tick): - accurate_pitch = self.make_pitch_accurate( - note.pitch - - 60 - - ( - 0 - if note.percussive - else MM_INSTRUMENT_DEVIATION_TABLE.get(note.instrument, 6) + accurate_pitch = ( + 0 + if note.percussive + else self.make_pitch_accurate( + note.pitch + - 60 + - MM_INSTRUMENT_DEVIATION_TABLE.get(note.instrument, 6) ) ) - print( - ":", - note.instrument, - note.pitch, - ">>", - accurate_pitch, - note.percussive, - note.duration_tick, - ) + # print( + # ":", + # note.instrument, + # note.pitch, + # ">>", + # accurate_pitch, + # note.percussive, + # note.duration_tick, + # ) if not note.percussive: overlay( self.res_data[note.instrument][accurate_pitch] diff --git a/Musicreater/data.py b/Musicreater/data.py index da967b1..e12e544 100644 --- a/Musicreater/data.py +++ b/Musicreater/data.py @@ -509,7 +509,7 @@ class SingleTrack(List[SingleNote]): self.argument_curves = {item: None for item in CurvableParam} - super().__init__(*args) + super().__init__(args) super().sort() @classmethod diff --git a/test_midi_preview.py b/test_midi_preview.py new file mode 100644 index 0000000..ad87b89 --- /dev/null +++ b/test_midi_preview.py @@ -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, +)