From 1d9931f79d7c9cad02dad8a685be84b95d886a72 Mon Sep 17 00:00:00 2001 From: EillesWan Date: Wed, 4 Feb 2026 00:06:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E7=BE=8E=EF=BC=8C=E5=90=8C=E5=BF=97?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E7=BE=8E=EF=BC=81=EF=BC=81=EF=BC=81=EF=BC=81?= =?UTF-8?q?=EF=BC=81=EF=BC=81=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Musicreater/__init__.py | 35 ++- Musicreater/_plugin_abc.py | 70 ++--- Musicreater/builtin_plugins/midi_read.py | 59 +++++ Musicreater/constants.py | 7 +- Musicreater/data.py | 31 ++- Musicreater/exceptions.py | 26 +- Musicreater/main.py | 247 ++++++++++++++++- Musicreater/plugins.py | 177 ++++++++----- Musicreater/types.py | 6 +- README.md | 2 +- README_EN.md | 2 +- TO-DO.md | 40 +++ .../Musicreater}/experiment.py | 0 .../Musicreater}/magicmain.py | 0 .../Musicreater}/old_exceptions.py | 0 .../Musicreater}/old_init.py | 0 .../Musicreater}/old_main.py | 0 .../Musicreater}/old_plugin/__init__.py | 0 .../old_plugin/addonpack/__init__.py | 0 .../Musicreater}/old_plugin/addonpack/main.py | 0 .../Musicreater}/old_plugin/archive.py | 0 .../Musicreater}/old_plugin/bdx.py | 0 .../old_plugin/bdxfile/__init__.py | 0 .../Musicreater}/old_plugin/bdxfile/main.py | 0 .../Musicreater}/old_plugin/common.py | 0 .../Musicreater}/old_plugin/main.py | 0 .../old_plugin/mcstructfile/__init__.py | 0 .../old_plugin/mcstructfile/main.py | 0 .../Musicreater}/old_plugin/mcstructure.py | 0 .../Musicreater}/old_plugin/noteblock.py | 0 .../Musicreater}/old_plugin/schematic.py | 0 .../old_plugin/schematic/__init__.py | 0 .../Musicreater}/old_plugin/schematic/main.py | 0 .../old_plugin/websocket/__init__.py | 0 .../Musicreater}/old_plugin/websocket/main.py | 0 .../Musicreater}/old_types.py | 0 .../Musicreater}/subclass.py | 0 .../Musicreater}/utils.py | 0 old-things/Packer/MSCT_MAIN.MPK | Bin 0 -> 8676 bytes old-things/Packer/MSCT_PLUGIN.MPK | Bin 0 -> 2283 bytes old-things/Packer/MSCT_PLUGIN_FUNCTION.MPK | 1 + {Packer => old-things/Packer}/MSCT_Packer.py | 0 old-things/Packer/checksum.txt | 6 + old-things/bgArrayLib/__init__.py | 0 old-things/bgArrayLib/bpm.py | 67 +++++ old-things/bgArrayLib/compute.py | 40 +++ old-things/bgArrayLib/instrumentConstant.py | 130 +++++++++ old-things/bgArrayLib/namesConstant.py | 250 ++++++++++++++++++ old-things/bgArrayLib/pitchStrConstant.py | 134 ++++++++++ old-things/bgArrayLib/reader.py | 208 +++++++++++++++ old-things/bgArrayLib/sy_resourcesPacker.py | 147 ++++++++++ example.py => old-things/example.py | 0 .../example_futureFunction.py | 0 .../example_singleConvert.py | 0 .../example_websocket.py | 0 old-things/fcwslib/LICENSE | 1 + old-things/fcwslib/__init__.py | 5 + old-things/fcwslib/server.py | 142 ++++++++++ .../let_future_java.py | 0 .../test_fsq_opera.py | 0 .../test_future_kamires.py | 0 .../test_future_lyric.py | 0 .../test_msq_opera.py | 0 pyproject.toml | 4 +- resources/msctDevAuthors.txt | 21 -- resources/poem.txt | 47 ---- .../test}/genexpr_vs_yieldfrom.py | 0 resources/音乐测试片段版权声明.txt | 2 +- test_read.py | 18 ++ 69 files changed, 1716 insertions(+), 209 deletions(-) create mode 100644 Musicreater/builtin_plugins/midi_read.py create mode 100644 TO-DO.md rename {Musicreater => old-things/Musicreater}/experiment.py (100%) rename {Musicreater => old-things/Musicreater}/magicmain.py (100%) rename {Musicreater => old-things/Musicreater}/old_exceptions.py (100%) rename {Musicreater => old-things/Musicreater}/old_init.py (100%) rename {Musicreater => old-things/Musicreater}/old_main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/addonpack/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/addonpack/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/archive.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/bdx.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/bdxfile/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/bdxfile/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/common.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/mcstructfile/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/mcstructfile/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/mcstructure.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/noteblock.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/schematic.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/schematic/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/schematic/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/websocket/__init__.py (100%) rename {Musicreater => old-things/Musicreater}/old_plugin/websocket/main.py (100%) rename {Musicreater => old-things/Musicreater}/old_types.py (100%) rename {Musicreater => old-things/Musicreater}/subclass.py (100%) rename {Musicreater => old-things/Musicreater}/utils.py (100%) create mode 100644 old-things/Packer/MSCT_MAIN.MPK create mode 100644 old-things/Packer/MSCT_PLUGIN.MPK create mode 100644 old-things/Packer/MSCT_PLUGIN_FUNCTION.MPK rename {Packer => old-things/Packer}/MSCT_Packer.py (100%) create mode 100644 old-things/Packer/checksum.txt create mode 100644 old-things/bgArrayLib/__init__.py create mode 100644 old-things/bgArrayLib/bpm.py create mode 100644 old-things/bgArrayLib/compute.py create mode 100644 old-things/bgArrayLib/instrumentConstant.py create mode 100644 old-things/bgArrayLib/namesConstant.py create mode 100644 old-things/bgArrayLib/pitchStrConstant.py create mode 100644 old-things/bgArrayLib/reader.py create mode 100644 old-things/bgArrayLib/sy_resourcesPacker.py rename example.py => old-things/example.py (100%) rename example_futureFunction.py => old-things/example_futureFunction.py (100%) rename example_singleConvert.py => old-things/example_singleConvert.py (100%) rename example_websocket.py => old-things/example_websocket.py (100%) create mode 100644 old-things/fcwslib/LICENSE create mode 100644 old-things/fcwslib/__init__.py create mode 100644 old-things/fcwslib/server.py rename let_future_java.py => old-things/let_future_java.py (100%) rename test_fsq_opera.py => old-things/test_fsq_opera.py (100%) rename test_future_kamires.py => old-things/test_future_kamires.py (100%) rename test_future_lyric.py => old-things/test_future_lyric.py (100%) rename test_msq_opera.py => old-things/test_msq_opera.py (100%) delete mode 100644 resources/msctDevAuthors.txt delete mode 100644 resources/poem.txt rename {tests => resources/test}/genexpr_vs_yieldfrom.py (100%) create mode 100644 test_read.py diff --git a/Musicreater/__init__.py b/Musicreater/__init__.py index d8f943a..a980ddd 100644 --- a/Musicreater/__init__.py +++ b/Musicreater/__init__.py @@ -27,7 +27,6 @@ https://gitee.com/TriM-Organization/Musicreater/blob/master/LICENSE.md。 # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md - __version__ = "3.0.0-alpha" __author__ = ( @@ -36,3 +35,37 @@ __author__ = ( ("鱼旧梦", "ElapsingDreams"), ("偷吃不是Touch", "Touch"), ) + +from .paramcurve import ParamCurve, InterpolationMethod, BoundaryBehaviour + +from .data import ( + SingleMusic, + SingleTrack, + SingleNote, + SoundAtmos, + MineNote, + CurvableParam, +) + +from .plugins import load_plugin_module + +from .main import MusiCreater + +__all__ = [ + "__version__", + "__author__", + # 参数曲线相关 + "ParamCurve", + "InterpolationMethod", + "BoundaryBehaviour", + # 音乐数据结构 + "SingleMusic", + "SingleTrack", + "SingleNote", + "SoundAtmos", + "MineNote", + "CurvableParam", + # 工程项目相关 + "load_plugin_module", + "MusiCreater", +] diff --git a/Musicreater/_plugin_abc.py b/Musicreater/_plugin_abc.py index a6fd87d..a121281 100644 --- a/Musicreater/_plugin_abc.py +++ b/Musicreater/_plugin_abc.py @@ -5,8 +5,8 @@ """ """ -版权所有 © 2025 金羿 -Copyright © 2025 Eilles +版权所有 © 2026 金羿 +Copyright © 2026 Eilles 开源相关声明请见 仓库根目录下的 License.md Terms & Conditions: License.md in the root directory @@ -26,7 +26,7 @@ Terms & Conditions: License.md in the root directory import sys from abc import ABC, abstractmethod -from dataclasses import dataclass +from dataclasses import dataclass, field from enum import Enum from pathlib import Path from typing import ( @@ -137,9 +137,12 @@ class PluginConfig(ABC): class PluginType(str, Enum): """插件类型枚举""" - FUNCTION_IMPORT = "import_data" - FUNCTION_EXPORT = "export_data" - FUNCTION_OPERATE = "data_operate" + FUNCTION_MUSIC_IMPORT = "import_music_data" + FUNCTION_TRACK_IMPORT = "import_track_data" + FUNCTION_MUSIC_OPERATE = "music_data_operating" + FUNCTION_TRACK_OPERATE = "track_data_operating" + FUNCTION_MUSIC_EXPORT = "export_music_data" + FUNCTION_TRACK_EXPORT = "export_track_data" SERVICE = "service" LIBRARY = "library" @@ -160,11 +163,11 @@ class PluginMetaInformation(ABC): """插件类型""" license: str = "MIT License" """插件发布时采用的许可协议""" - dependencies: Sequence[str] = [] + dependencies: Sequence[str] = tuple() """插件是否对其他插件存在依赖""" -class TopBasePlugin(ABC): +class TopPluginBase(ABC): """所有插件的抽象基类""" metainfo: PluginMetaInformation @@ -180,14 +183,15 @@ class TopBasePlugin(ABC): ) ) else: - raise PluginMetainfoNotFoundError( - "类`{cls_name}`必须定义一个`metainfo`属性。".format( - cls_name=cls.__name__ + if not cls.__name__.endswith("PluginBase"): + raise PluginMetainfoNotFoundError( + "类`{cls_name}`必须定义一个`metainfo`属性。".format( + cls_name=cls.__name__ + ) ) - ) -class TopInOutBasePlugin(TopBasePlugin, ABC): +class TopInOutPluginBase(TopPluginBase, ABC): """导入导出用抽象基类""" supported_formats: Tuple[str, ...] = tuple() @@ -218,15 +222,15 @@ class TopInOutBasePlugin(TopBasePlugin, ABC): return format_name.upper().endswith(self.supported_formats) -class MusicInputPlugin(TopInOutBasePlugin, ABC): +class MusicInputPluginBase(TopInOutPluginBase, ABC): """导入用插件抽象基类-完整曲目""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_IMPORT: + if cls.metainfo.type != PluginType.FUNCTION_MUSIC_IMPORT: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`MusicInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`MusicInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_MUSIC_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -245,15 +249,15 @@ class MusicInputPlugin(TopInOutBasePlugin, ABC): return self.loadbytes(f, config) -class TrackInputPlugin(TopInOutBasePlugin, ABC): +class TrackInputPluginBase(TopInOutPluginBase, ABC): """导入用插件抽象基类-单个音轨""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_IMPORT: + if cls.metainfo.type != PluginType.FUNCTION_TRACK_IMPORT: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`TrackInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`TrackInputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_TRACK_IMPORT`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -272,15 +276,15 @@ class TrackInputPlugin(TopInOutBasePlugin, ABC): return self.loadbytes(f, config) -class MusicOperatePlugin(TopBasePlugin, ABC): +class MusicOperatePluginBase(TopPluginBase, ABC): """音乐处理用插件抽象基类-完整曲目""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_OPERATE: + if cls.metainfo.type != PluginType.FUNCTION_MUSIC_OPERATE: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`MusicOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`MusicOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_MUSIC_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -294,15 +298,15 @@ class MusicOperatePlugin(TopBasePlugin, ABC): pass -class TrackOperatePlugin(TopBasePlugin, ABC): +class TrackOperatePluginBase(TopPluginBase, ABC): """音乐处理用插件抽象基类-单个音轨""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_OPERATE: + if cls.metainfo.type != PluginType.FUNCTION_TRACK_OPERATE: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`TrackOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`TrackOperatePlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_TRACK_OPERATE`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -316,15 +320,15 @@ class TrackOperatePlugin(TopBasePlugin, ABC): pass -class MusicOutputPlugin(TopInOutBasePlugin, ABC): +class MusicOutputPluginBase(TopInOutPluginBase, ABC): """导出用插件的抽象基类-完整曲目""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_EXPORT: + if cls.metainfo.type != PluginType.FUNCTION_MUSIC_EXPORT: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`MusicOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`MusicOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_MUSIC_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -345,15 +349,15 @@ class MusicOutputPlugin(TopInOutBasePlugin, ABC): pass -class TrackOutputPlugin(TopInOutBasePlugin, ABC): +class TrackOutputPluginBase(TopInOutPluginBase, ABC): """导出用插件的抽象基类-单个音轨""" def __init_subclass__(cls) -> None: super().__init_subclass__() - if cls.metainfo.type != PluginType.FUNCTION_EXPORT: + if cls.metainfo.type != PluginType.FUNCTION_TRACK_EXPORT: raise PluginMetainfoValueError( - "插件类`{cls_name}`是从`TrackOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format( + "插件类`{cls_name}`是从`TrackOutputPlugin`继承的,该类的子类应当为一个`PluginType.FUNCTION_TRACK_EXPORT`类型的插件,而不是`PluginType.{cls_type}`".format( cls_name=cls.__name__, cls_type=cls.metainfo.type.name, ) @@ -374,7 +378,7 @@ class TrackOutputPlugin(TopInOutBasePlugin, ABC): pass -class ServicePlugin(TopBasePlugin, ABC): +class ServicePluginBase(TopPluginBase, ABC): """服务插件抽象基类""" def __init_subclass__(cls) -> None: @@ -394,7 +398,7 @@ class ServicePlugin(TopBasePlugin, ABC): pass -class LibraryPlugin(TopBasePlugin, ABC): +class LibraryPluginBase(TopPluginBase, ABC): """插件依赖库的抽象基类""" def __init_subclass__(cls) -> None: diff --git a/Musicreater/builtin_plugins/midi_read.py b/Musicreater/builtin_plugins/midi_read.py new file mode 100644 index 0000000..ead0134 --- /dev/null +++ b/Musicreater/builtin_plugins/midi_read.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +""" +音·创 v3 内置的 Midi 读取插件 +""" + +""" +版权所有 © 2026 金羿、玉衡Alioth +Copyright © 2026 Eilles, YuhengAlioth + +开源相关声明请见 仓库根目录下的 License.md +Terms & Conditions: License.md in the root directory +""" + +# 睿乐组织 开发交流群 861684859 +# Email TriM-Organization@hotmail.com +# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md + +import mido + +from pathlib import Path + +from typing import BinaryIO, Optional + +from Musicreater import SingleMusic +from Musicreater.plugins import ( + music_input_plugin, + PluginConfig, + PluginMetaInformation, + PluginType, + MusicInputPluginBase, +) + + +@music_input_plugin("midi_2_music_plugin") +class MidiImport2MusicPlugin(MusicInputPluginBase): + """Midi 音乐数据导入插件""" + + metainfo = PluginMetaInformation( + name="midi_2_music_plugin", + author="金羿、玉衡Alioth", + description="从 Midi 文件导入音乐数据", + version=(0, 0, 1), + type=PluginType.FUNCTION_MUSIC_IMPORT, + license="Same as Musicreater", + ) + + supported_formats = ("MID", "MIDI") + + def loadbytes( + self, bytes_buffer_in: BinaryIO, config: PluginConfig | None + ) -> SingleMusic: + midi_file = mido.MidiFile(file=bytes_buffer_in) + return SingleMusic() # =========================== TODO: 等待制作 + + def load(self, file_path: Path, config: Optional[PluginConfig]) -> "SingleMusic": + """从 Midi 文件导入音乐数据""" + midi_file = mido.MidiFile(filename=file_path) + return SingleMusic() # =========================== TODO: 等待制作 diff --git a/Musicreater/constants.py b/Musicreater/constants.py index c2f3848..14450cc 100644 --- a/Musicreater/constants.py +++ b/Musicreater/constants.py @@ -5,8 +5,8 @@ """ """ -版权所有 © 2025 金羿 & 诸葛亮与八卦阵 -Copyright © 2025 Eilles & bgArray +版权所有 © 2026 金羿 & 诸葛亮与八卦阵 +Copyright © 2026 Eilles & bgArray 开源相关声明请见 仓库根目录下的 License.md Terms & Conditions: License.md in the root directory @@ -44,9 +44,6 @@ MIDI_PAN = "pan" """Midi通道立体声场偏移""" - - - # Midi用对照表 MIDI_DEFAULT_VOLUME_VALUE: int = ( diff --git a/Musicreater/data.py b/Musicreater/data.py index fd6a3e6..ed71940 100644 --- a/Musicreater/data.py +++ b/Musicreater/data.py @@ -421,7 +421,7 @@ class SingleTrack(List[SingleNote]): track_name: str """轨道之名称""" - is_enabled: bool + is_enabled: bool = True """该音轨是否启用""" track_instrument: str @@ -453,16 +453,12 @@ class SingleTrack(List[SingleNote]): precise_time: bool = True, percussion: bool = False, sound_direction: SoundAtmos = SoundAtmos(), - enabled: bool = True, extra_information: Dict[str, Any] = {}, *args: SingleNote, ): self.track_name = name """音轨名称""" - self.is_enabled = enabled - """音轨启用情况""" - self.track_instrument = instrument """乐器ID""" @@ -492,6 +488,21 @@ class SingleTrack(List[SingleNote]): super().__init__(*args) super().sort() + def disable(self) -> None: + """禁用音轨""" + + self.is_enabled = False + + def enable(self) -> None: + """启用音轨""" + + self.is_enabled = True + + def toggle_able(self) -> None: + """切换音轨的启用状态""" + + self.is_enabled = not self.is_enabled + def append(self, object: SingleNote) -> None: """ 添加一个音符,推荐使用 add 方法 @@ -728,13 +739,15 @@ class SingleMusic(List[SingleTrack]): self, start_time: float, end_time: float = inf ) -> Generator[Iterator[SingleNote], Any, None]: """获取指定时间段的各个音轨的音符数据""" - return (track.get_notes(start_time, end_time) for track in self) + return (track.get_notes(start_time, end_time) for track in self.music_tracks) def get_tracked_minenotes( self, start_time: float, end_time: float = inf ) -> Generator[Iterator[MineNote], Any, None]: """获取指定时间段的各个音轨的,供我的世界播放的音符数据类""" - return (track.get_minenotes(start_time, end_time) for track in self) + return ( + track.get_minenotes(start_time, end_time) for track in self.music_tracks + ) def get_notes( self, start_time: float, end_time: float = inf @@ -743,7 +756,7 @@ class SingleMusic(List[SingleTrack]): if self.track_amount == 0: return iter(()) return self.yield_from_tracks( - [track.get_notes(start_time, end_time) for track in self], + [track.get_notes(start_time, end_time) for track in self.music_tracks], sort_key=lambda x: x.start_time, ) @@ -754,7 +767,7 @@ class SingleMusic(List[SingleTrack]): if self.track_amount == 0: return yield from self.yield_from_tracks( - [track.get_minenotes(start_time, end_time) for track in self], + [track.get_minenotes(start_time, end_time) for track in self.music_tracks], sort_key=lambda x: x.start_tick, ) diff --git a/Musicreater/exceptions.py b/Musicreater/exceptions.py index 037a894..fa96b02 100644 --- a/Musicreater/exceptions.py +++ b/Musicreater/exceptions.py @@ -5,8 +5,8 @@ """ """ -版权所有 © 2025 金羿 & 玉衡Alioth -Copyright © 2025 Eilles & YuhengAlioth +版权所有 © 2026 金羿 & 玉衡Alioth +Copyright © 2026 Eilles & YuhengAlioth 开源相关声明请见 仓库根目录下的 License.md Terms & Conditions: License.md in the root directory @@ -56,6 +56,7 @@ class MusicreaterInnerlyError(MusicreaterBaseException): """内部错误(面向开发者的报错信息)""" super().__init__("内部错误 - ", *args) + class MusicreaterOuterlyError(MusicreaterBaseException): """外部错误""" @@ -64,8 +65,6 @@ class MusicreaterOuterlyError(MusicreaterBaseException): super().__init__("外部错误 - ", *args) - - class InnerlyParameterError(MusicreaterInnerlyError): """内部传参错误""" @@ -90,6 +89,13 @@ class ParameterValueError(InnerlyParameterError, ValueError): super().__init__("参数数值错误:", *args) +class PluginNotSpecifiedError(InnerlyParameterError, LookupError): + """未指定插件""" + + def __init__(self, *args): + """未指定插件""" + super().__init__("未指定插件:", *args) + class OuterlyParameterError(MusicreaterOuterlyError): """外部参数错误""" @@ -115,6 +121,12 @@ class IllegalMinimumVolumeError(OuterlyParameterError, ValueError): super().__init__("最小播放音量超出范围:", *args) +class FileFormatNotSupportedError(MusicreaterOuterlyError): + """不支持的文件格式""" + + def __init__(self, *args): + """文件格式不受支持""" + super().__init__("不支持的文件格式:", *args) class NoteBinaryDecodeError(MusicreaterOuterlyError): @@ -148,6 +160,7 @@ class NoteBinaryFileVerificationFailed(NoteBinaryDecodeError): """音乐存储文件与其校验值不一致""" super().__init__("音乐存储文件校验失败:", *args) + class PluginDefineError(MusicreaterInnerlyError): """插件定义错误(内部相关)""" @@ -155,6 +168,7 @@ class PluginDefineError(MusicreaterInnerlyError): """插件本身存在错误""" super().__init__("插件内部错误 - ", *args) + class PluginInstanceNotFoundError(PluginDefineError, LookupError): """插件实例未找到""" @@ -162,6 +176,7 @@ class PluginInstanceNotFoundError(PluginDefineError, LookupError): """插件实例未找到""" super().__init__("插件实例未找到:", *args) + class PluginAttributeNotFoundError(PluginDefineError, AttributeError): """插件属性定义错误""" @@ -177,6 +192,7 @@ class PluginMetainfoError(PluginDefineError): """插件元信息定义错误""" super().__init__("插件元信息定义错误 - ", *args) + class PluginMetainfoTypeError(PluginMetainfoError, TypeError): """插件元信息定义类型错误""" @@ -184,6 +200,7 @@ class PluginMetainfoTypeError(PluginMetainfoError, TypeError): """插件元信息定义类型错误""" super().__init__("插件元信息类型错误:", *args) + class PluginMetainfoValueError(PluginMetainfoError, ValueError): """插件元信息定义值错误""" @@ -191,6 +208,7 @@ class PluginMetainfoValueError(PluginMetainfoError, ValueError): """插件元信息定义值错误""" super().__init__("插件元信息数值错误:", *args) + class PluginMetainfoNotFoundError(PluginMetainfoError, PluginAttributeNotFoundError): """插件元信息定义缺少错误""" diff --git a/Musicreater/main.py b/Musicreater/main.py index b8e08af..ed88499 100644 --- a/Musicreater/main.py +++ b/Musicreater/main.py @@ -43,13 +43,24 @@ https://gitee.com/TriM-Organization/Musicreater/blob/master/LICENSE.md。 # Words combine! Codes unite! # Hurry to call the programmer! Let's Go! +import re + +from difflib import get_close_matches from typing import Dict, Generator, List, Optional, Tuple, Union from pathlib import Path + from .data import SingleMusic, SingleTrack -from ._plugin_abc import TopBasePlugin -from .plugins import __global_plugin_registry, PluginRegistry +from .exceptions import FileFormatNotSupportedError, PluginNotSpecifiedError +from ._plugin_abc import TopPluginBase +from .plugins import ( + _global_plugin_registry, + PluginRegistry, + PluginConfig, + PluginType, + load_plugin_module, +) class MusiCreater: @@ -60,21 +71,239 @@ class MusiCreater: __plugin_registry: PluginRegistry """插件注册表实例""" - _plugin_cache: Dict[str, TopBasePlugin] + _plugin_cache: Dict[str, TopPluginBase] """插件缓存字典,插件名为键、插件实例为值""" music: SingleMusic """当前曲目实例""" def __init__(self, whole_music: SingleMusic) -> None: - global __global_plugin_registry + global _global_plugin_registry - self.__plugin_registry = __global_plugin_registry + self.__plugin_registry = _global_plugin_registry self._plugin_cache = {} + self._cache_all_plugins() self.music = whole_music - - - - def import_music(self, file_path: Path, plugin_name: Optional[str] = None) -> SingleMusic: \ No newline at end of file + @classmethod + def import_music( + cls, + file_path: Path, + plugin_name: Optional[str] = None, + plugin_config: Optional[PluginConfig] = None, + ): + __music = None + if plugin_name: + __music = _global_plugin_registry.get_music_input_plugin(plugin_name).load( + file_path, plugin_config + ) + else: + for plugin in _global_plugin_registry.get_music_input_plugin_by_format( + file_path + ): + if __music is not None: + raise PluginNotSpecifiedError( + "文件类型`{}`可被多个插件处理,请在导入函数的参数中指定插件名称".format( + file_path.suffix.upper() + ) + ) + __music = plugin.load(file_path, plugin_config) + if __music is None: + raise FileFormatNotSupportedError( + "无法找到处理`{}`类型文件的插件".format(file_path.suffix.upper()) + ) + return cls(whole_music=__music) + + def import_track( + self, + file_path: Path, + plugin_name: Optional[str] = None, + plugin_config: Optional[PluginConfig] = None, + ) -> SingleTrack: + __track = None + if plugin_name: + __track = self.get_plugin_by_name( + plugin_name + ).load( # pyright: ignore[reportAttributeAccessIssue] + file_path, plugin_config + ) + else: + for plugin in self.__plugin_registry.get_track_input_plugin_by_format( + file_path + ): + if __track: + raise PluginNotSpecifiedError( + "文件类型`{}`可被多个插件处理,请在导入函数的参数中指定插件名称".format( + file_path.suffix.upper() + ) + ) + __track = plugin.load(file_path, plugin_config) + if __track: + self.music.append(__track) + return __track + raise FileFormatNotSupportedError( + "无法找到处理`{}`类型文件的插件".format(file_path.suffix.upper()) + ) + + def export_music( + self, + file_path: Path, + plugin_name: Optional[str] = None, + plugin_config: Optional[PluginConfig] = None, + ) -> None: + __plugin = None + if plugin_name: + __plugin = self.get_plugin_by_name(plugin_name) + else: + for plugin in self.__plugin_registry.get_music_output_plugin_by_format( + file_path + ): + if __plugin: + raise PluginNotSpecifiedError( + "文件类型`{}`可被多个插件处理,请在导出函数的参数中指定插件名称".format( + file_path.suffix.upper() + ) + ) + __plugin = plugin + + if __plugin: + __plugin.dump( # pyright: ignore[reportAttributeAccessIssue] + self.music, file_path, plugin_config + ) + else: + raise FileFormatNotSupportedError( + "无法找到处理`{}`类型文件的插件".format(file_path.suffix.upper()) + ) + + def export_track( + self, + track_index: int, + file_path: Path, + plugin_name: Optional[str] = None, + plugin_config: Optional[PluginConfig] = None, + ) -> None: + __plugin = None + if plugin_name: + __plugin = self.get_plugin_by_name(plugin_name) + else: + for plugin in self.__plugin_registry.get_track_output_plugin_by_format( + file_path + ): + if __plugin: + raise PluginNotSpecifiedError( + "文件类型`{}`可被多个插件处理,请在导出函数的参数中指定插件名称".format( + file_path.suffix.upper() + ) + ) + __plugin = plugin + + if __plugin: + __plugin.dump( # pyright: ignore[reportAttributeAccessIssue] + self.music[track_index], file_path, plugin_config + ) + else: + raise FileFormatNotSupportedError( + "无法找到处理`{}`类型文件的插件".format(file_path.suffix.upper()) + ) + + def perform_operation_on_music( + self, plugin_name: str, plugin_config: Optional[PluginConfig] = None + ): + # 这样做是为了兼容以后的*撤回/重做*功能 + self.music = self.get_plugin_by_name( + plugin_name + ).process( # pyright: ignore[reportAttributeAccessIssue] + self.music, plugin_config + ) + + def perform_operation_on_track( + self, + track_index: int, + plugin_name: str, + plugin_config: Optional[PluginConfig] = None, + ): + # 这样做是为了兼容以后的*撤回/重做*功能 + self.music[track_index] = self.get_plugin_by_name( + plugin_name + ).process( # pyright: ignore[reportAttributeAccessIssue] + self.music[track_index], plugin_config + ) + + @staticmethod + def _camel_to_snake(name: str) -> str: + """ + 将驼峰命名转换为蛇形命名 + CyberAngel -> cyber_angel + """ + return re.sub( + "([a-z0-9])([A-Z])", r"\1_\2", re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) + ).lower() + + def _parse_plugin_name(self, attr_name: str) -> Optional[str]: + """解析属性名称为插件名称""" + + # 尝试去除 _plugin 后缀 + if attr_name.endswith("_plugin"): + candidate_name = attr_name[:-7] # 去除 "_plugin" + if candidate_name in self._plugin_cache: + return candidate_name + + # 尝试转换为 snake_case(如果插件名是驼峰式) + snake_case_name = self._camel_to_snake(attr_name) + + if snake_case_name != attr_name: # 避免重复转换 + if snake_case_name in self._plugin_cache: # 尝试转换后的插件名 + return snake_case_name + else: + return self._parse_plugin_name(snake_case_name) + + return None + + def _get_closest_plugin_name(self, requested_name: str) -> Optional[str]: + """找到最接近的插件名称(用于更好的错误提示)""" + + matches = get_close_matches( + requested_name, self._plugin_cache.keys(), n=1, cutoff=0.6 + ) + return matches[0] if matches else None + + def get_plugin_by_name(self, name: str) -> TopPluginBase: + """获取插件实例,并缓存起来,提高性能""" + if name.startswith("_"): + raise AttributeError("属性`{}`不存在,不应访问类的私有属性".format(name)) + + if name in self._plugin_cache: + return self._plugin_cache[name] + else: + plugin_name = self._parse_plugin_name(name) + if plugin_name: + self._plugin_cache[name] = self._plugin_cache[plugin_name] + return self._plugin_cache[name] + + closest = self._get_closest_plugin_name(name) + + raise AttributeError( + "插件`{}`不存在,请检查插件名称是否正确".format(name) + + ( + ";或者阁下可能想要使用的是`{}`插件?".format(closest) + if closest + else "" + ) + ) + + def __getattr__(self, name: str): + """动态属性访问,允许直接 实例.插件名 来访问插件""" + return self.get_plugin_by_name(name) + + def _cache_all_plugins(self): + """获取所有已注册插件的名称""" + for __plugin_type, __plugins_set in self.__plugin_registry: + for __plugin in __plugins_set: + if __plugin.metainfo.name in self._plugin_cache: # 避免重复缓存 + if ( + __plugin.metainfo.version + <= self._plugin_cache[__plugin.metainfo.name].metainfo.version + ): # 优先使用版本号最大的插件 + continue + self._plugin_cache[__plugin.metainfo.name] = __plugin diff --git a/Musicreater/plugins.py b/Musicreater/plugins.py index 2563fd4..14bb224 100644 --- a/Musicreater/plugins.py +++ b/Musicreater/plugins.py @@ -5,8 +5,8 @@ """ """ -版权所有 © 2025 金羿 -Copyright © 2025 Eilles +版权所有 © 2026 金羿 +Copyright © 2026 Eilles 开源相关声明请见 仓库根目录下的 License.md Terms & Conditions: License.md in the root directory @@ -19,7 +19,18 @@ Terms & Conditions: License.md in the root directory import importlib from pathlib import Path -from typing import Dict, Any, Optional, List, Tuple, Union, Generator, Set +from typing import ( + Dict, + Any, + Optional, + List, + Tuple, + Union, + Generator, + Set, + Iterable, + Iterator, +) from itertools import chain @@ -30,14 +41,16 @@ from ._plugin_abc import ( PluginConfig, PluginMetaInformation, # 抽象基类(插件定义) - MusicInputPlugin, - TrackInputPlugin, - MusicOperatePlugin, - TrackOperatePlugin, - MusicOutputPlugin, - TrackOutputPlugin, - ServicePlugin, - LibraryPlugin, + MusicInputPluginBase, + TrackInputPluginBase, + MusicOperatePluginBase, + TrackOperatePluginBase, + MusicOutputPluginBase, + TrackOutputPluginBase, + ServicePluginBase, + LibraryPluginBase, + # 顶层插件定义 + TopPluginBase, ) from .exceptions import ( PluginMetainfoNotFoundError, @@ -53,14 +66,14 @@ __all__ = [ "PluginConfig", "PluginMetaInformation", # 抽象基类(插件定义) - "MusicInputPlugin", - "TrackInputPlugin", - "MusicOperatePlugin", - "TrackOperatePlugin", - "MusicOutputPlugin", - "TrackOutputPlugin", - "ServicePlugin", - "LibraryPlugin", + "MusicInputPluginBase", + "TrackInputPluginBase", + "MusicOperatePluginBase", + "TrackOperatePluginBase", + "MusicOutputPluginBase", + "TrackOutputPluginBase", + "ServicePluginBase", + "LibraryPluginBase", # 插件注册用装饰函数 "music_input_plugin", "track_input_plugin", @@ -102,14 +115,34 @@ class PluginRegistry: # (不用 Dict[str`plugin name`, PluginClass`] 的形式) # 啊,我真的很高尚 # 你真的不会把插件注册两遍吧……对吧? - self._music_input_plugins: Set[MusicInputPlugin] = set() - self._track_input_plugins: Set[TrackInputPlugin] = set() - self._music_operate_plugins: Set[MusicOperatePlugin] = set() - self._track_operate_plugins: Set[TrackOperatePlugin] = set() - self._music_output_plugins: Set[MusicOutputPlugin] = set() - self._track_output_plugins: Set[TrackOutputPlugin] = set() - self._service_plugins: Set[ServicePlugin] = set() - self._library_plugins: Set[LibraryPlugin] = set() + + # EMERGENCY TODO ================================================ CRITICAL 紧急更改 + # 改成 Dict[str`plugin id`, PluginClass`]] 的形式吧 + # 刚刚才想起来,这个 name 是显示名称啊!草 + # 现在测试情况下就将错就错吧,先把 name 当成 id 来写吧 + self._music_input_plugins: Set[MusicInputPluginBase] = set() + self._track_input_plugins: Set[TrackInputPluginBase] = set() + self._music_operate_plugins: Set[MusicOperatePluginBase] = set() + self._track_operate_plugins: Set[TrackOperatePluginBase] = set() + self._music_output_plugins: Set[MusicOutputPluginBase] = set() + self._track_output_plugins: Set[TrackOutputPluginBase] = set() + self._service_plugins: Set[ServicePluginBase] = set() + self._library_plugins: Set[LibraryPluginBase] = set() + + def __iter__(self) -> Iterator[Tuple[PluginType, Set[TopPluginBase]]]: + """迭代器,返回所有插件""" + return iter( + ( + (PluginType.FUNCTION_MUSIC_IMPORT, self._music_input_plugins), + (PluginType.FUNCTION_TRACK_IMPORT, self._track_input_plugins), + (PluginType.FUNCTION_MUSIC_OPERATE, self._music_operate_plugins), + (PluginType.FUNCTION_TRACK_OPERATE, self._track_operate_plugins), + (PluginType.FUNCTION_MUSIC_EXPORT, self._music_output_plugins), + (PluginType.FUNCTION_TRACK_EXPORT, self._track_output_plugins), + (PluginType.SERVICE, self._service_plugins), + (PluginType.LIBRARY, self._library_plugins), + ) + ) # pyright: ignore[reportReturnType] def register_music_input_plugin(self, plugin_class: type) -> None: """注册输入插件-整首曲目""" @@ -145,7 +178,7 @@ class PluginRegistry: def get_music_input_plugin_by_format( self, filepath_or_format: Union[Path, str] - ) -> Generator[MusicInputPlugin, None, None]: + ) -> Generator[MusicInputPluginBase, None, None]: """通过指定输入的文件或格式,以获取对应的全曲导入用插件""" if isinstance(filepath_or_format, str): return ( @@ -168,7 +201,7 @@ class PluginRegistry: def get_track_input_plugin_by_format( self, filepath_or_format: Union[Path, str] - ) -> Generator[TrackInputPlugin, None, None]: + ) -> Generator[TrackInputPluginBase, None, None]: """通过指定输入的文件或格式,以获取对应的单音轨导入用插件""" if isinstance(filepath_or_format, str): return ( @@ -191,7 +224,7 @@ class PluginRegistry: def get_music_output_plugin_by_format( self, filepath_or_format: Union[Path, str] - ) -> Generator[MusicOutputPlugin, None, None]: + ) -> Generator[MusicOutputPluginBase, None, None]: """通过指定输出的文件或格式,以获取对应的导出全曲用插件""" if isinstance(filepath_or_format, str): return ( @@ -214,7 +247,7 @@ class PluginRegistry: def get_track_output_plugin_by_format( self, filepath_or_format: Union[Path, str] - ) -> Generator[TrackOutputPlugin, None, None]: + ) -> Generator[TrackOutputPluginBase, None, None]: """通过指定输出的文件或格式,以获取对应的导出单个音轨用插件""" if isinstance(filepath_or_format, str): return ( @@ -235,7 +268,7 @@ class PluginRegistry: ) ) - def get_music_input_plugin(self, plugin_name: str) -> MusicInputPlugin: + def get_music_input_plugin(self, plugin_name: str) -> MusicInputPluginBase: """获取指定名称的全曲导入用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -251,7 +284,7 @@ class PluginRegistry: "未找到“用于导入曲目、名为`{}`”的插件".format(plugin_name) ) - def get_track_input_plugin(self, plugin_name: str) -> TrackInputPlugin: + def get_track_input_plugin(self, plugin_name: str) -> TrackInputPluginBase: """获取指定名称的单音轨导入用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -267,7 +300,7 @@ class PluginRegistry: "未找到“用于导入单个音轨、名为`{}`”的插件".format(plugin_name) ) - def get_music_operate_plugin(self, plugin_name: str) -> MusicOperatePlugin: + def get_music_operate_plugin(self, plugin_name: str) -> MusicOperatePluginBase: """获取指定名称的全曲处理用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -283,7 +316,7 @@ class PluginRegistry: "未找到“用于处理整个曲目、名为`{}`”的插件".format(plugin_name) ) - def get_track_operate_plugin(self, plugin_name: str) -> TrackOperatePlugin: + def get_track_operate_plugin(self, plugin_name: str) -> TrackOperatePluginBase: """获取指定名称的单音轨处理用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -299,7 +332,7 @@ class PluginRegistry: "未找到“用于处理单个音轨、名为`{}`”的插件".format(plugin_name) ) - def get_music_output_plugin(self, plugin_name: str) -> MusicOutputPlugin: + def get_music_output_plugin(self, plugin_name: str) -> MusicOutputPluginBase: """获取指定名称的导出全曲用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -315,7 +348,7 @@ class PluginRegistry: "未找到“用于导出完整曲目、名为`{}`”的插件".format(plugin_name) ) - def get_track_output_plugin(self, plugin_name: str) -> TrackOutputPlugin: + def get_track_output_plugin(self, plugin_name: str) -> TrackOutputPluginBase: """获取指定名称的导出单音轨用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -331,7 +364,7 @@ class PluginRegistry: "未找到“用于导出单个音轨、名为`{}`”的插件".format(plugin_name) ) - def get_service_plugin(self, plugin_name: str) -> ServicePlugin: + def get_service_plugin(self, plugin_name: str) -> ServicePluginBase: """获取服务用插件,当名称重叠时,取版本号最大的""" try: return max( @@ -347,7 +380,7 @@ class PluginRegistry: "未找到名为`{}`的服务用插件".format(plugin_name) ) - def get_library_plugin(self, plugin_name: str) -> LibraryPlugin: + def get_library_plugin(self, plugin_name: str) -> LibraryPluginBase: """获取依赖库类插件,当名称重叠时,取版本号最高的""" try: return max( @@ -386,101 +419,101 @@ class PluginRegistry: ) -__global_plugin_registry = PluginRegistry() +_global_plugin_registry = PluginRegistry() """全局插件注册表实例""" -def music_input_plugin(metainfo: PluginMetaInformation): +def music_input_plugin(plugin_id: str): """全曲输入用插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_music_input_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_music_input_plugin(cls) return cls return decorator -def track_input_plugin(metainfo: PluginMetaInformation): +def track_input_plugin(plugin_id: str): """单轨输入用插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_track_input_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_track_input_plugin(cls) return cls return decorator -def music_operate_plugin(metainfo: PluginMetaInformation): +def music_operate_plugin(plugin_id: str): """全曲处理用插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_music_operate_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_music_operate_plugin(cls) return cls return decorator -def track_operate_plugin(metainfo: PluginMetaInformation): +def track_operate_plugin(plugin_id: str): """音轨处理插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_track_operate_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_track_operate_plugin(cls) return cls return decorator -def music_output_plugin(metainfo: PluginMetaInformation): +def music_output_plugin(plugin_id: str): """乐曲输出用插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_music_output_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_music_output_plugin(cls) return cls return decorator -def track_output_plugin(metainfo: PluginMetaInformation): +def track_output_plugin(plugin_id: str): """音轨输出用插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_track_output_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_track_output_plugin(cls) return cls return decorator -def service_plugin(metainfo: PluginMetaInformation): +def service_plugin(plugin_id: str): """服务插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_service_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_service_plugin(cls) return cls return decorator -def library_plugin(metainfo: PluginMetaInformation): +def library_plugin(plugin_id: str): """支持库插件装饰器""" def decorator(cls): - global __global_plugin_registry - cls.metainfo = metainfo - __global_plugin_registry.register_library_plugin(cls) + global _global_plugin_registry + cls.id = plugin_id + _global_plugin_registry.register_library_plugin(cls) return cls return decorator diff --git a/Musicreater/types.py b/Musicreater/types.py index 6cd114a..9010b95 100644 --- a/Musicreater/types.py +++ b/Musicreater/types.py @@ -5,8 +5,8 @@ """ """ -版权所有 © 2025 金羿 & 玉衡Alioth -Copyright © 2025 Eilles & YuhengAlioth +版权所有 © 2026 金羿 & 玉衡Alioth +Copyright © 2026 Eilles & YuhengAlioth 开源相关声明请见 仓库根目录下的 License.md Terms & Conditions: License.md in the root directory @@ -22,4 +22,4 @@ from typing import Callable, Dict, List, Literal, Mapping, Tuple, Union FittingFunctionType = Callable[[float], float] """ 拟合函数类型 -""" \ No newline at end of file +""" diff --git a/README.md b/README.md index 4a77550..9f43211 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ pip install --upgrade -i https://pypi.python.org/simple Musicreater ``` -- 克隆仓库并安装(最新版本但**不推荐**) +- 克隆仓库并安装(最新内容但**不推荐**) ```bash git clone https://gitee.com/TriM-Organization/Musicreater.git diff --git a/README_EN.md b/README_EN.md index 7444c14..dd59bca 100644 --- a/README_EN.md +++ b/README_EN.md @@ -35,7 +35,7 @@ [简体中文 🇨🇳](README.md) | English🇬🇧 -**Notice that the localizations of documents may NOT be up-to-date.** +**Notice that the localizations of documents may probably NOT be up-to-date. The original document is in Chinese.** ## Introduction🚀 diff --git a/TO-DO.md b/TO-DO.md new file mode 100644 index 0000000..4953bfc --- /dev/null +++ b/TO-DO.md @@ -0,0 +1,40 @@ +# 任务清单 + +## 待办事项 +- 乐曲文件格式设计 + 目前想到的是: + 1. 使用 `.MCT` 作为项目文件的后缀,然后考虑一下格式是否和之前的 MusicSequence 兼容,如果兼容的话可以照旧用 `.MSQ`,如不的话,可以试试想一个新的后缀名作为数据文件后缀 + 2. 要求数据文件支持完全流式读入 + +- 音轨静音处理 + 当前没有处理 + +- 优化音轨的存储方式 + 当前是用列表,且每一次变动元素都要重新排序,这样消耗太大了,需要优化,改用最小堆形式(heapq) + +- 移植 v2 功能到内置插件 + 目前 v2 的功能有很多,都要移植到 v3。 + 1. 导入 Midi 文件到全曲 + 2. 导入 Midi 文件到指定轨道 + 3. 导出到延迟播放器的结构文件(MCSTRUCTURE、BDX) + 4. 导出到延迟播放器的附加包 + 5. 导出到积分板播放器的以上两种形式 + 6. 导出到中继器播放器的以上两种形式 + 7. 在 WebSocket 播放器中播放 + 8. 导出到支持神羽资源包的以上 7 种形式 + 9. 对于 Midi 歌词的实验性功能 + 10. 对于 Java 版本适配的实验性功能 + 11. 对于听感优化的实验性功能(插值、偏移) + +- 测试参数曲线的功能 + +- 支持导出音符盒构成的音乐 + +- 支持导出成 schematic 结构 + +## 讨论 + +1. 是否应该在插件注册表 PluginRegistry 中采用 `Dict[插件名, 插件对象]` 的形式存储插件? + 当前不采用这种方式是认为可以兼容一些极端场景下用户将一堆同名插件放在一起的情况。但是就算是插件放在一起,我们也可以有选择地读入注册表,比如依照版本号只读取最高版本的插件,并不需要全部存储在插件注册表中。所以其实用字典来存储是有利的?吗? + +2. 服务插件到底该怎么写?总不能留着一个 PluginType.SERVICE 的插件一直空在那里吧…… diff --git a/Musicreater/experiment.py b/old-things/Musicreater/experiment.py similarity index 100% rename from Musicreater/experiment.py rename to old-things/Musicreater/experiment.py diff --git a/Musicreater/magicmain.py b/old-things/Musicreater/magicmain.py similarity index 100% rename from Musicreater/magicmain.py rename to old-things/Musicreater/magicmain.py diff --git a/Musicreater/old_exceptions.py b/old-things/Musicreater/old_exceptions.py similarity index 100% rename from Musicreater/old_exceptions.py rename to old-things/Musicreater/old_exceptions.py diff --git a/Musicreater/old_init.py b/old-things/Musicreater/old_init.py similarity index 100% rename from Musicreater/old_init.py rename to old-things/Musicreater/old_init.py diff --git a/Musicreater/old_main.py b/old-things/Musicreater/old_main.py similarity index 100% rename from Musicreater/old_main.py rename to old-things/Musicreater/old_main.py diff --git a/Musicreater/old_plugin/__init__.py b/old-things/Musicreater/old_plugin/__init__.py similarity index 100% rename from Musicreater/old_plugin/__init__.py rename to old-things/Musicreater/old_plugin/__init__.py diff --git a/Musicreater/old_plugin/addonpack/__init__.py b/old-things/Musicreater/old_plugin/addonpack/__init__.py similarity index 100% rename from Musicreater/old_plugin/addonpack/__init__.py rename to old-things/Musicreater/old_plugin/addonpack/__init__.py diff --git a/Musicreater/old_plugin/addonpack/main.py b/old-things/Musicreater/old_plugin/addonpack/main.py similarity index 100% rename from Musicreater/old_plugin/addonpack/main.py rename to old-things/Musicreater/old_plugin/addonpack/main.py diff --git a/Musicreater/old_plugin/archive.py b/old-things/Musicreater/old_plugin/archive.py similarity index 100% rename from Musicreater/old_plugin/archive.py rename to old-things/Musicreater/old_plugin/archive.py diff --git a/Musicreater/old_plugin/bdx.py b/old-things/Musicreater/old_plugin/bdx.py similarity index 100% rename from Musicreater/old_plugin/bdx.py rename to old-things/Musicreater/old_plugin/bdx.py diff --git a/Musicreater/old_plugin/bdxfile/__init__.py b/old-things/Musicreater/old_plugin/bdxfile/__init__.py similarity index 100% rename from Musicreater/old_plugin/bdxfile/__init__.py rename to old-things/Musicreater/old_plugin/bdxfile/__init__.py diff --git a/Musicreater/old_plugin/bdxfile/main.py b/old-things/Musicreater/old_plugin/bdxfile/main.py similarity index 100% rename from Musicreater/old_plugin/bdxfile/main.py rename to old-things/Musicreater/old_plugin/bdxfile/main.py diff --git a/Musicreater/old_plugin/common.py b/old-things/Musicreater/old_plugin/common.py similarity index 100% rename from Musicreater/old_plugin/common.py rename to old-things/Musicreater/old_plugin/common.py diff --git a/Musicreater/old_plugin/main.py b/old-things/Musicreater/old_plugin/main.py similarity index 100% rename from Musicreater/old_plugin/main.py rename to old-things/Musicreater/old_plugin/main.py diff --git a/Musicreater/old_plugin/mcstructfile/__init__.py b/old-things/Musicreater/old_plugin/mcstructfile/__init__.py similarity index 100% rename from Musicreater/old_plugin/mcstructfile/__init__.py rename to old-things/Musicreater/old_plugin/mcstructfile/__init__.py diff --git a/Musicreater/old_plugin/mcstructfile/main.py b/old-things/Musicreater/old_plugin/mcstructfile/main.py similarity index 100% rename from Musicreater/old_plugin/mcstructfile/main.py rename to old-things/Musicreater/old_plugin/mcstructfile/main.py diff --git a/Musicreater/old_plugin/mcstructure.py b/old-things/Musicreater/old_plugin/mcstructure.py similarity index 100% rename from Musicreater/old_plugin/mcstructure.py rename to old-things/Musicreater/old_plugin/mcstructure.py diff --git a/Musicreater/old_plugin/noteblock.py b/old-things/Musicreater/old_plugin/noteblock.py similarity index 100% rename from Musicreater/old_plugin/noteblock.py rename to old-things/Musicreater/old_plugin/noteblock.py diff --git a/Musicreater/old_plugin/schematic.py b/old-things/Musicreater/old_plugin/schematic.py similarity index 100% rename from Musicreater/old_plugin/schematic.py rename to old-things/Musicreater/old_plugin/schematic.py diff --git a/Musicreater/old_plugin/schematic/__init__.py b/old-things/Musicreater/old_plugin/schematic/__init__.py similarity index 100% rename from Musicreater/old_plugin/schematic/__init__.py rename to old-things/Musicreater/old_plugin/schematic/__init__.py diff --git a/Musicreater/old_plugin/schematic/main.py b/old-things/Musicreater/old_plugin/schematic/main.py similarity index 100% rename from Musicreater/old_plugin/schematic/main.py rename to old-things/Musicreater/old_plugin/schematic/main.py diff --git a/Musicreater/old_plugin/websocket/__init__.py b/old-things/Musicreater/old_plugin/websocket/__init__.py similarity index 100% rename from Musicreater/old_plugin/websocket/__init__.py rename to old-things/Musicreater/old_plugin/websocket/__init__.py diff --git a/Musicreater/old_plugin/websocket/main.py b/old-things/Musicreater/old_plugin/websocket/main.py similarity index 100% rename from Musicreater/old_plugin/websocket/main.py rename to old-things/Musicreater/old_plugin/websocket/main.py diff --git a/Musicreater/old_types.py b/old-things/Musicreater/old_types.py similarity index 100% rename from Musicreater/old_types.py rename to old-things/Musicreater/old_types.py diff --git a/Musicreater/subclass.py b/old-things/Musicreater/subclass.py similarity index 100% rename from Musicreater/subclass.py rename to old-things/Musicreater/subclass.py diff --git a/Musicreater/utils.py b/old-things/Musicreater/utils.py similarity index 100% rename from Musicreater/utils.py rename to old-things/Musicreater/utils.py diff --git a/old-things/Packer/MSCT_MAIN.MPK b/old-things/Packer/MSCT_MAIN.MPK new file mode 100644 index 0000000000000000000000000000000000000000..99a80f19165117b9c606d5af36f839bbb357d2ac GIT binary patch literal 8676 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 CblO?~ literal 0 HcmV?d00001 diff --git a/old-things/Packer/MSCT_PLUGIN.MPK b/old-things/Packer/MSCT_PLUGIN.MPK new file mode 100644 index 0000000000000000000000000000000000000000..d9f2a64d4716ac9deacd499070fff2d0d648bf2b GIT binary patch literal 2283 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 FZ8{P*VBP=# literal 0 HcmV?d00001 diff --git a/old-things/Packer/MSCT_PLUGIN_FUNCTION.MPK b/old-things/Packer/MSCT_PLUGIN_FUNCTION.MPK new file mode 100644 index 0000000..5145948 --- /dev/null +++ b/old-things/Packer/MSCT_PLUGIN_FUNCTION.MPK @@ -0,0 +1 @@ +q@v,fxm5]s"BMXinZ8=4PTUQmGu_ߑDS| [ȉ؊20a-5+{4#ji0w fs68c,"&&!霳?4 ^R)|c \ No newline at end of file diff --git a/Packer/MSCT_Packer.py b/old-things/Packer/MSCT_Packer.py similarity index 100% rename from Packer/MSCT_Packer.py rename to old-things/Packer/MSCT_Packer.py diff --git a/old-things/Packer/checksum.txt b/old-things/Packer/checksum.txt new file mode 100644 index 0000000..5cd26d1 --- /dev/null +++ b/old-things/Packer/checksum.txt @@ -0,0 +1,6 @@ +MSCT_MAIN: +6b9f5a97d50beb07c834e375104c67ae44c57ae40f73fb71075b3668899029c7 +MSCT_PLUGIN: +c280413a394a539438a5d10078c9b55f04bcd4cf6869c59a3f7a026039748cfc +MSCT_PLUGIN_FUNCTION: +40697f1d9b293268fe142fa3e9bffee2923a8f4811ec7bbdf7b14afb98723ef2 \ No newline at end of file diff --git a/old-things/bgArrayLib/__init__.py b/old-things/bgArrayLib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/old-things/bgArrayLib/bpm.py b/old-things/bgArrayLib/bpm.py new file mode 100644 index 0000000..3c8299e --- /dev/null +++ b/old-things/bgArrayLib/bpm.py @@ -0,0 +1,67 @@ +import mido +import numpy + +''' +bpm +bites per minutes +每分钟的拍数 +''' + +def mt2gt(mt, tpb_a, bpm_a): + return round(mt / tpb_a / bpm_a * 60) + + +def get(mid:mido.MidiFile) -> int: + '''传入一个 MidiFile, 返回其音乐的bpm + :param mid : mido.MidFile + mido库识别的midi文件数据 + :return bpm : int + ''' + # mid = mido.MidiFile(mf) + length = mid.length + tpb = mid.ticks_per_beat + bpm = 20 + gotV = 0 + + for track in mid.tracks: + global_time = 0 + for msg in track: + global_time += msg.time + if msg.type == "note_on" and msg.velocity > 0: + gotV = mt2gt(global_time, tpb, bpm) + errorV = numpy.fabs(gotV - length) + last_dic = {bpm: errorV} + if last_dic.get(bpm) > errorV: + last_dic = {bpm: errorV} + bpm += 2 + + while True: + for track in mid.tracks: + global_time = 0 + for msg in track: + global_time += msg.time + if msg.type == "note_on" and msg.velocity > 0: + gotV = mt2gt(global_time, tpb, bpm) + errorV = numpy.fabs(gotV - length) + try: + if last_dic.get(bpm - 2) > errorV: + last_dic = {bpm: errorV} + except TypeError: + pass + bpm += 2 + if bpm >= 252: + break + print(list(last_dic.keys())[0]) + return list(last_dic.keys())[0] + + +def compute(mid:mido.MidiFile): + answer = 60000000/mid.ticks_per_beat + print(answer) + return answer + + +if __name__ == '__main__': + mid = mido.MidiFile(r"C:\Users\lc\Documents\MuseScore3\乐谱\乐谱\Bad style - Time back.mid") + get(mid) + compute(mid) diff --git a/old-things/bgArrayLib/compute.py b/old-things/bgArrayLib/compute.py new file mode 100644 index 0000000..e783f7a --- /dev/null +++ b/old-things/bgArrayLib/compute.py @@ -0,0 +1,40 @@ +def round_up(num, power=0): + """ + 实现精确四舍五入,包含正、负小数多种场景 + :param num: 需要四舍五入的小数 + :param power: 四舍五入位数,支持0-∞ + :return: 返回四舍五入后的结果 + """ + try: + print(1 / 0) + except ZeroDivisionError: + digit = 10 ** power + num2 = float(int(num * digit)) + # 处理正数,power不为0的情况 + if num >= 0 and power != 0: + tag = num * digit - num2 + 1 / (digit * 10) + if tag >= 0.5: + return (num2 + 1) / digit + else: + return num2 / digit + # 处理正数,power为0取整的情况 + elif num >= 0 and power == 0: + tag = num * digit - int(num) + if tag >= 0.5: + return (num2 + 1) / digit + else: + return num2 / digit + # 处理负数,power为0取整的情况 + elif power == 0 and num < 0: + tag = num * digit - int(num) + if tag <= -0.5: + return (num2 - 1) / digit + else: + return num2 / digit + # 处理负数,power不为0的情况 + else: + tag = num * digit - num2 - 1 / (digit * 10) + if tag <= -0.5: + return (num2 - 1) / digit + else: + return num2 / digit diff --git a/old-things/bgArrayLib/instrumentConstant.py b/old-things/bgArrayLib/instrumentConstant.py new file mode 100644 index 0000000..13eeb0f --- /dev/null +++ b/old-things/bgArrayLib/instrumentConstant.py @@ -0,0 +1,130 @@ +instrument_list = { + "0": "harp", + "1": "harp", + "2": "pling", + "3": "harp", + "4": "pling", + "5": "pling", + "6": "harp", + "7": "harp", + "8": "share", + "9": "harp", + "10": "didgeridoo", + "11": "harp", + "12": "xylophone", + "13": "chime", + "14": "harp", + "15": "harp", + "16": "bass", + "17": "harp", + "18": "harp", + "19": "harp", + "20": "harp", + "21": "harp", + "22": "harp", + "23": "guitar", + "24": "guitar", + "25": "guitar", + "26": "guitar", + "27": "guitar", + "28": "guitar", + "29": "guitar", + "30": "guitar", + "31": "bass", + "32": "bass", + "33": "bass", + "34": "bass", + "35": "bass", + "36": "bass", + "37": "bass", + "38": "bass", + "39": "bass", + "40": "harp", + "41": "harp", + "42": "harp", + "43": "harp", + "44": "iron_xylophone", + "45": "guitar", + "46": "harp", + "47": "harp", + "48": "guitar", + "49": "guitar", + "50": "bit", + "51": "bit", + "52": "harp", + "53": "harp", + "54": "bit", + "55": "flute", + "56": "flute", + "57": "flute", + "58": "flute", + "59": "flute", + "60": "flute", + "61": "flute", + "62": "flute", + "63": "flute", + "64": "bit", + "65": "bit", + "66": "bit", + "67": "bit", + "68": "flute", + "69": "harp", + "70": "harp", + "71": "flute", + "72": "flute", + "73": "flute", + "74": "harp", + "75": "flute", + "76": "harp", + "77": "harp", + "78": "harp", + "79": "harp", + "80": "bit", + "81": "bit", + "82": "bit", + "83": "bit", + "84": "bit", + "85": "bit", + "86": "bit", + "87": "bit", + "88": "bit", + "89": "bit", + "90": "bit", + "91": "bit", + "92": "bit", + "93": "bit", + "94": "bit", + "95": "bit", + "96": "bit", + "97": "bit", + "98": "bit", + "99": "bit", + "100": "bit", + "101": "bit", + "102": "bit", + "103": "bit", + "104": "harp", + "105": "banjo", + "106": "harp", + "107": "harp", + "108": "harp", + "109": "harp", + "110": "harp", + "111": "guitar", + "112": "harp", + "113": "bell", + "114": "harp", + "115": "cow_bell", + "116": "basedrum", + "117": "bass", + "118": "bit", + "119": "basedrum", + "120": "guitar", + "121": "harp", + "122": "harp", + "123": "harp", + "124": "harp", + "125": "hat", + "126": "basedrum", + "127": "snare", +} diff --git a/old-things/bgArrayLib/namesConstant.py b/old-things/bgArrayLib/namesConstant.py new file mode 100644 index 0000000..0b77c0c --- /dev/null +++ b/old-things/bgArrayLib/namesConstant.py @@ -0,0 +1,250 @@ +zip_name = { + -1: "-1.Acoustic_Kit_打击乐.zip", + 0: "0.Acoustic_Grand_Piano_大钢琴.zip", + 1: "1.Bright_Acoustic_Piano_亮音大钢琴.zip", + 10: "10.Music_Box_八音盒.zip", + 100: "100.FX_brightness_合成特效-亮音.zip", + 101: "101.FX_goblins_合成特效-小妖.zip", + 102: "102.FX_echoes_合成特效-回声.zip", + 103: "103.FX_sci-fi_合成特效-科幻.zip", + 104: "104.Sitar_锡塔尔.zip", + 105: "105.Banjo_班卓.zip", + 106: "106.Shamisen_三味线.zip", + 107: "107.Koto_筝.zip", + 108: "108.Kalimba_卡林巴.zip", + 109: "109.Bagpipe_风笛.zip", + 11: "11.Vibraphone_电颤琴.zip", + 110: "110.Fiddle_古提琴.zip", + 111: "111.Shanai_唢呐.zip", + 112: "112.Tinkle_Bell_铃铛.zip", + 113: "113.Agogo_拉丁打铃.zip", + 114: "114.Steel_Drums_钢鼓.zip", + 115: "115.Woodblock_木块.zip", + 116: "116.Taiko_Drum_太鼓.zip", + 117: "117.Melodic_Tom_嗵鼓.zip", + 118: "118.Synth_Drum_合成鼓.zip", + 119: "119.Reverse_Cymbal_镲波形反转.zip", + 12: "12.Marimba_马林巴.zip", + 13: "13.Xylophone_木琴.zip", + 14: "14.Tubular_Bells_管钟.zip", + 15: "15.Dulcimer_扬琴.zip", + 16: "16.Drawbar_Organ_击杆风琴.zip", + 17: "17.Percussive_Organ_打击型风琴.zip", + 18: "18.Rock_Organ_摇滚风琴.zip", + 19: "19.Church_Organ_管风琴.zip", + 2: "2.Electric_Grand_Piano_电子大钢琴.zip", + 20: "20.Reed_Organ_簧风琴.zip", + 21: "21.Accordion_手风琴.zip", + 22: "22.Harmonica_口琴.zip", + 23: "23.Tango_Accordian_探戈手风琴.zip", + 24: "24.Acoustic_Guitar_(nylon)_尼龙弦吉他.zip", + 25: "25.Acoustic_Guitar(steel)_钢弦吉他.zip", + 26: "26.Electric_Guitar_(jazz)_爵士乐电吉他.zip", + 27: "27.Electric_Guitar_(clean)_清音电吉他.zip", + 28: "28.Electric_Guitar_(muted)_弱音电吉他.zip", + 29: "29.Overdriven_Guitar_驱动音效吉他.zip", + 3: "3.Honky-Tonk_Piano_酒吧钢琴.zip", + 30: "30.Distortion_Guitar_失真音效吉他.zip", + 31: "31.Guitar_Harmonics_吉他泛音.zip", + 32: "32.Acoustic_Bass_原声贝司.zip", + 33: "33.Electric_Bass(finger)_指拨电贝司.zip", + 34: "34.Electric_Bass(pick)_拨片拨电贝司.zip", + 35: "35.Fretless_Bass_无品贝司.zip", + 36: "36.Slap_Bass_A_击弦贝司A.zip", + 37: "37.Slap_Bass_B_击弦贝司B.zip", + 38: "38.Synth_Bass_A_合成贝司A.zip", + 39: "39.Synth_Bass_B_合成贝司B.zip", + 4: "4.Electric_Piano_1_电钢琴A.zip", + 40: "40.Violin_小提琴.zip", + 41: "41.Viola_中提琴.zip", + 42: "42.Cello_大提琴.zip", + 43: "43.Contrabass_低音提琴.zip", + 44: "44.Tremolo_Strings_弦乐震音.zip", + 45: "45.Pizzicato_Strings_弦乐拨奏.zip", + 46: "46.Orchestral_Harp_竖琴.zip", + 47: "47.Timpani_定音鼓.zip", + 48: "48.String_Ensemble_A_弦乐合奏A.zip", + 49: "49.String_Ensemble_B_弦乐合奏B.zip", + 5: "5.Electric_Piano_2_电钢琴B.zip", + 50: "50.SynthStrings_A_合成弦乐A.zip", + 51: "51.SynthStrings_B_合成弦乐B.zip", + 52: "52.Choir_Aahs_合唱“啊”音.zip", + 53: "53.Voice_Oohs_人声“哦”音.zip", + 54: "54.Synth_Voice_合成人声.zip", + 55: "55.Orchestra_Hit_乐队打击乐.zip", + 56: "56.Trumpet_小号.zip", + 57: "57.Trombone_长号.zip", + 58: "58.Tuba_大号.zip", + 59: "59.Muted_Trumpet_弱音小号.zip", + 6: "6.Harpsichord_拨弦古钢琴.zip", + 60: "60.French_Horn_圆号.zip", + 61: "61.Brass_Section_铜管组.zip", + 62: "62.Synth_Brass_A_合成铜管A.zip", + 63: "63.Synth_Brass_A_合成铜管B.zip", + 64: "64.Soprano_Sax_高音萨克斯.zip", + 65: "65.Alto_Sax_中音萨克斯.zip", + 66: "66.Tenor_Sax_次中音萨克斯.zip", + 67: "67.Baritone_Sax_上低音萨克斯.zip", + 68: "68.Oboe_双簧管.zip", + 69: "69.English_Horn_英国管.zip", + 7: "7.Clavinet_击弦古钢琴.zip", + 70: "70.Bassoon_大管.zip", + 71: "71.Clarinet_单簧管.zip", + 72: "72.Piccolo_短笛.zip", + 73: "73.Flute_长笛.zip", + 74: "74.Recorder_竖笛.zip", + 75: "75.Pan_Flute_排笛.zip", + 76: "76.Bottle_Blow_吹瓶口.zip", + 77: "77.Skakuhachi_尺八.zip", + 78: "78.Whistle_哨.zip", + 79: "79.Ocarina_洋埙.zip", + 8: "8.Celesta_钢片琴.zip", + 80: "80.Lead_square_合成主音-方波.zip", + 81: "81.Lead_sawtooth_合成主音-锯齿波.zip", + 82: "82.Lead_calliope_lead_合成主音-汽笛风琴.zip", + 83: "83.Lead_chiff_lead_合成主音-吹管.zip", + 84: "84.Lead_charang_合成主音5-吉他.zip", + 85: "85.Lead_voice_合成主音-人声.zip", + 86: "86.Lead_fifths_合成主音-五度.zip", + 87: "87.Lead_bass+lead_合成主音-低音加主音.zip", + 88: "88.Pad_new_age_合成柔音-新时代.zip", + 89: "89.Pad_warm_合成柔音-暖音.zip", + 9: "9.Glockenspiel_钟琴.zip", + 90: "90.Pad_polysynth_合成柔音-复合成.zip", + 91: "91.Pad_choir_合成柔音-合唱.zip", + 92: "92.Pad_bowed_合成柔音-弓弦.zip", + 93: "93.Pad_metallic_合成柔音-金属.zip", + 94: "94.Pad_halo_合成柔音-光环.zip", + 95: "95.Pad_sweep_合成柔音-扫弦.zip", + 96: "96.FX_rain_合成特效-雨.zip", + 97: "97.FX_soundtrack_合成特效-音轨.zip", + 98: "98.FX_crystal_合成特效-水晶.zip", + 99: "99.FX_atmosphere_合成特效-大气.zip", +} + +mcpack_name = { + -1: "-1.Acoustic_Kit_打击乐.mcpack", + 0: "0.Acoustic_Grand_Piano_大钢琴.mcpack", + 1: "1.Bright_Acoustic_Piano_亮音大钢琴.mcpack", + 10: "10.Music_Box_八音盒.mcpack", + 100: "100.FX_brightness_合成特效-亮音.mcpack", + 101: "101.FX_goblins_合成特效-小妖.mcpack", + 102: "102.FX_echoes_合成特效-回声.mcpack", + 103: "103.FX_sci-fi_合成特效-科幻.mcpack", + 104: "104.Sitar_锡塔尔.mcpack", + 105: "105.Banjo_班卓.mcpack", + 106: "106.Shamisen_三味线.mcpack", + 107: "107.Koto_筝.mcpack", + 108: "108.Kalimba_卡林巴.mcpack", + 109: "109.Bagpipe_风笛.mcpack", + 11: "11.Vibraphone_电颤琴.mcpack", + 110: "110.Fiddle_古提琴.mcpack", + 111: "111.Shanai_唢呐.mcpack", + 112: "112.Tinkle_Bell_铃铛.mcpack", + 113: "113.Agogo_拉丁打铃.mcpack", + 114: "114.Steel_Drums_钢鼓.mcpack", + 115: "115.Woodblock_木块.mcpack", + 116: "116.Taiko_Drum_太鼓.mcpack", + 117: "117.Melodic_Tom_嗵鼓.mcpack", + 118: "118.Synth_Drum_合成鼓.mcpack", + 119: "119.Reverse_Cymbal_镲波形反转.mcpack", + 12: "12.Marimba_马林巴.mcpack", + 13: "13.Xylophone_木琴.mcpack", + 14: "14.Tubular_Bells_管钟.mcpack", + 15: "15.Dulcimer_扬琴.mcpack", + 16: "16.Drawbar_Organ_击杆风琴.mcpack", + 17: "17.Percussive_Organ_打击型风琴.mcpack", + 18: "18.Rock_Organ_摇滚风琴.mcpack", + 19: "19.Church_Organ_管风琴.mcpack", + 2: "2.Electric_Grand_Piano_电子大钢琴.mcpack", + 20: "20.Reed_Organ_簧风琴.mcpack", + 21: "21.Accordion_手风琴.mcpack", + 22: "22.Harmonica_口琴.mcpack", + 23: "23.Tango_Accordian_探戈手风琴.mcpack", + 24: "24.Acoustic_Guitar_(nylon)_尼龙弦吉他.mcpack", + 25: "25.Acoustic_Guitar(steel)_钢弦吉他.mcpack", + 26: "26.Electric_Guitar_(jazz)_爵士乐电吉他.mcpack", + 27: "27.Electric_Guitar_(clean)_清音电吉他.mcpack", + 28: "28.Electric_Guitar_(muted)_弱音电吉他.mcpack", + 29: "29.Overdriven_Guitar_驱动音效吉他.mcpack", + 3: "3.Honky-Tonk_Piano_酒吧钢琴.mcpack", + 30: "30.Distortion_Guitar_失真音效吉他.mcpack", + 31: "31.Guitar_Harmonics_吉他泛音.mcpack", + 32: "32.Acoustic_Bass_原声贝司.mcpack", + 33: "33.Electric_Bass(finger)_指拨电贝司.mcpack", + 34: "34.Electric_Bass(pick)_拨片拨电贝司.mcpack", + 35: "35.Fretless_Bass_无品贝司.mcpack", + 36: "36.Slap_Bass_A_击弦贝司A.mcpack", + 37: "37.Slap_Bass_B_击弦贝司B.mcpack", + 38: "38.Synth_Bass_A_合成贝司A.mcpack", + 39: "39.Synth_Bass_B_合成贝司B.mcpack", + 4: "4.Electric_Piano_1_电钢琴A.mcpack", + 40: "40.Violin_小提琴.mcpack", + 41: "41.Viola_中提琴.mcpack", + 42: "42.Cello_大提琴.mcpack", + 43: "43.Contrabass_低音提琴.mcpack", + 44: "44.Tremolo_Strings_弦乐震音.mcpack", + 45: "45.Pizzicato_Strings_弦乐拨奏.mcpack", + 46: "46.Orchestral_Harp_竖琴.mcpack", + 47: "47.Timpani_定音鼓.mcpack", + 48: "48.String_Ensemble_A_弦乐合奏A.mcpack", + 49: "49.String_Ensemble_B_弦乐合奏B.mcpack", + 5: "5.Electric_Piano_2_电钢琴B.mcpack", + 50: "50.SynthStrings_A_合成弦乐A.mcpack", + 51: "51.SynthStrings_B_合成弦乐B.mcpack", + 52: "52.Choir_Aahs_合唱“啊”音.mcpack", + 53: "53.Voice_Oohs_人声“哦”音.mcpack", + 54: "54.Synth_Voice_合成人声.mcpack", + 55: "55.Orchestra_Hit_乐队打击乐.mcpack", + 56: "56.Trumpet_小号.mcpack", + 57: "57.Trombone_长号.mcpack", + 58: "58.Tuba_大号.mcpack", + 59: "59.Muted_Trumpet_弱音小号.mcpack", + 6: "6.Harpsichord_拨弦古钢琴.mcpack", + 60: "60.French_Horn_圆号.mcpack", + 61: "61.Brass_Section_铜管组.mcpack", + 62: "62.Synth_Brass_A_合成铜管A.mcpack", + 63: "63.Synth_Brass_A_合成铜管B.mcpack", + 64: "64.Soprano_Sax_高音萨克斯.mcpack", + 65: "65.Alto_Sax_中音萨克斯.mcpack", + 66: "66.Tenor_Sax_次中音萨克斯.mcpack", + 67: "67.Baritone_Sax_上低音萨克斯.mcpack", + 68: "68.Oboe_双簧管.mcpack", + 69: "69.English_Horn_英国管.mcpack", + 7: "7.Clavinet_击弦古钢琴.mcpack", + 70: "70.Bassoon_大管.mcpack", + 71: "71.Clarinet_单簧管.mcpack", + 72: "72.Piccolo_短笛.mcpack", + 73: "73.Flute_长笛.mcpack", + 74: "74.Recorder_竖笛.mcpack", + 75: "75.Pan_Flute_排笛.mcpack", + 76: "76.Bottle_Blow_吹瓶口.mcpack", + 77: "77.Skakuhachi_尺八.mcpack", + 78: "78.Whistle_哨.mcpack", + 79: "79.Ocarina_洋埙.mcpack", + 8: "8.Celesta_钢片琴.mcpack", + 80: "80.Lead_square_合成主音-方波.mcpack", + 81: "81.Lead_sawtooth_合成主音-锯齿波.mcpack", + 82: "82.Lead_calliope_lead_合成主音-汽笛风琴.mcpack", + 83: "83.Lead_chiff_lead_合成主音-吹管.mcpack", + 84: "84.Lead_charang_合成主音5-吉他.mcpack", + 85: "85.Lead_voice_合成主音-人声.mcpack", + 86: "86.Lead_fifths_合成主音-五度.mcpack", + 87: "87.Lead_bass+lead_合成主音-低音加主音.mcpack", + 88: "88.Pad_new_age_合成柔音-新时代.mcpack", + 89: "89.Pad_warm_合成柔音-暖音.mcpack", + 9: "9.Glockenspiel_钟琴.mcpack", + 90: "90.Pad_polysynth_合成柔音-复合成.mcpack", + 91: "91.Pad_choir_合成柔音-合唱.mcpack", + 92: "92.Pad_bowed_合成柔音-弓弦.mcpack", + 93: "93.Pad_metallic_合成柔音-金属.mcpack", + 94: "94.Pad_halo_合成柔音-光环.mcpack", + 95: "95.Pad_sweep_合成柔音-扫弦.mcpack", + 96: "96.FX_rain_合成特效-雨.mcpack", + 97: "97.FX_soundtrack_合成特效-音轨.mcpack", + 98: "98.FX_crystal_合成特效-水晶.mcpack", + 99: "99.FX_atmosphere_合成特效-大气.mcpack", +} + +if __name__ == "__main__": + print(zip_name[0]) diff --git a/old-things/bgArrayLib/pitchStrConstant.py b/old-things/bgArrayLib/pitchStrConstant.py new file mode 100644 index 0000000..1128336 --- /dev/null +++ b/old-things/bgArrayLib/pitchStrConstant.py @@ -0,0 +1,134 @@ +pitch = { + "0": "0.0220970869120796", + "1": "0.0234110480761981", + "2": "0.0248031414370031", + "3": "0.0262780129766786", + "4": "0.0278405849418856", + "5": "0.0294960722713029", + "6": "0.03125", + "7": "0.033108221698728", + "8": "0.0350769390096679", + "9": "0.037162722343835", + "10": "0.0393725328092148", + "11": "0.0417137454428136", + "12": "0.0441941738241592", + "13": "0.0468220961523963", + "14": "0.0496062828740062", + "15": "0.0525560259533572", + "16": "0.0556811698837712", + "17": "0.0589921445426059", + "18": "0.0625", + "19": "0.066216443397456", + "20": "0.0701538780193358", + "21": "0.0743254446876701", + "22": "0.0787450656184296", + "23": "0.0834274908856271", + "24": "0.0883883476483184", + "25": "0.0936441923047926", + "26": "0.0992125657480125", + "27": "0.105112051906714", + "28": "0.111362339767542", + "29": "0.117984289085212", + "30": "0.125", + "31": "0.132432886794912", + "32": "0.140307756038672", + "33": "0.14865088937534", + "34": "0.157490131236859", + "35": "0.166854981771254", + "36": "0.176776695296637", + "37": "0.187288384609585", + "38": "0.198425131496025", + "39": "0.210224103813429", + "40": "0.222724679535085", + "41": "0.235968578170423", + "42": "0.25", + "43": "0.264865773589824", + "44": "0.280615512077343", + "45": "0.29730177875068", + "46": "0.314980262473718", + "47": "0.333709963542509", + "48": "0.353553390593274", + "49": "0.37457676921917", + "50": "0.39685026299205", + "51": "0.420448207626857", + "52": "0.44544935907017", + "53": "0.471937156340847", + "54": "0.5", + "55": "0.529731547179648", + "56": "0.561231024154687", + "57": "0.594603557501361", + "58": "0.629960524947437", + "59": "0.667419927085017", + "60": "0.707106781186548", + "61": "0.749153538438341", + "62": "0.7937005259841", + "63": "0.840896415253715", + "64": "0.890898718140339", + "65": "0.943874312681694", + "66": "1", + "67": "1.0594630943593", + "68": "1.12246204830937", + "69": "1.18920711500272", + "70": "1.25992104989487", + "71": "1.33483985417003", + "72": "1.4142135623731", + "73": "1.49830707687668", + "74": "1.5874010519682", + "75": "1.68179283050743", + "76": "1.78179743628068", + "77": "1.88774862536339", + "78": "2", + "79": "2.11892618871859", + "80": "2.24492409661875", + "81": "2.37841423000544", + "82": "2.51984209978975", + "83": "2.66967970834007", + "84": "2.82842712474619", + "85": "2.99661415375336", + "86": "3.1748021039364", + "87": "3.36358566101486", + "88": "3.56359487256136", + "89": "3.77549725072677", + "90": "4", + "91": "4.23785237743718", + "92": "4.48984819323749", + "93": "4.75682846001088", + "94": "5.03968419957949", + "95": "5.33935941668014", + "96": "5.65685424949238", + "97": "5.99322830750673", + "98": "6.3496042078728", + "99": "6.72717132202972", + "100": "7.12718974512272", + "101": "7.55099450145355", + "102": "8", + "103": "8.47570475487436", + "104": "8.97969638647498", + "105": "9.51365692002177", + "106": "10.079368399159", + "107": "10.6787188333603", + "108": "11.3137084989848", + "109": "11.9864566150135", + "110": "12.6992084157456", + "111": "13.4543426440594", + "112": "14.2543794902454", + "113": "15.1019890029071", + "114": "16", + "115": "16.9514095097487", + "116": "17.95939277295", + "117": "19.0273138400435", + "118": "20.158736798318", + "119": "21.3574376667206", + "120": "22.6274169979695", + "121": "23.9729132300269", + "122": "25.3984168314912", + "123": "26.9086852881189", + "124": "28.5087589804909", + "125": "30.2039780058142", + "126": "32", + "127": "33.9028190194974", + "128": "35.9187855458999", + "129": "38.0546276800871", + "130": "40.3174735966359", + "131": "42.7148753334411", +} diff --git a/old-things/bgArrayLib/reader.py b/old-things/bgArrayLib/reader.py new file mode 100644 index 0000000..b668bf7 --- /dev/null +++ b/old-things/bgArrayLib/reader.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- + + +# from nmcsup.log import log +import pickle + + +class Note: + def __init__(self, channel, pitch, velocity, time, time_position, instrument): + self.channel = channel + self.pitch = pitch + self.velocity = velocity + self.delay = time + self.time_position = time_position + self.instrument = instrument + self.CD = "d" + + def get_CD(self, start, end): + if end - start > 1.00: + self.CD = "c" + else: + self.CD = "d" + + +def midiNewReader(midfile: str): + import mido + + # from msctspt.threadOpera import NewThread + from bgArrayLib.bpm import get + + def Time(mt, tpb_a, bpm_a): + return round(mt / tpb_a / bpm_a * 60 * 20) + + Notes = [] + tracks = [] + note_list = [] + close = [] + on = [] + off = [] + instruments = [] + isPercussion = False + try: + mid = mido.MidiFile(midfile) + except Exception: + print("找不到文件或无法读取文件" + midfile) + return False + tpb = mid.ticks_per_beat + bpm = get(mid) + # 解析 + # def loadMidi(track1): + for track in mid.tracks: + overallTime = 0.0 + instrument = 0 + for i in track: + overallTime += i.time + try: + if i.channel != 9: + # try: + # log("event_type(事件): " + str(i.type) + " channel(音轨): " + str(i.channel) + + # " note/pitch(音高): " + + # str(i[2]) + + # " velocity(力度): " + str(i.velocity) + " time(间隔时间): " + str(i.time) + + # " overallTime/globalTime/timePosition: " + str(overallTime) + " \n") + # except AttributeError: + # log("event_type(事件): " + str(i.type) + " thing(内容):" + str(i) + " \n") + if "program_change" in str(i): + instrument = i.program + if instrument > 119: # 音色不够 + pass + else: + instruments.append(i.program) + if "note_on" in str(i) and i.velocity > 0: + print(i) + # print(i.note) + # print([Note(i.channel, i.note, i.velocity, i.time, Time(overallTime, tpb, bpm), instrument)]) + tracks.append( + [ + Note( + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + instrument, + ) + ] + ) + note_list.append( + [ + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + instrument, + ] + ) + on.append([i.note, Time(overallTime, tpb, bpm)]) + # return [Note(i.channel, i, i.velocity, i.time, Time(overallTime, tpb, bpm))] + if "note_off" in str(i) or "note_on" in str(i) and i.velocity == 0: + # print(i) + # print([Note(i.channel, i.note, i.velocity, i.time, Time(overallTime, tpb, bpm))]) + close.append( + [ + Note( + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + instrument, + ) + ] + ) + off.append([i.note, Time(overallTime, tpb, bpm)]) + # return [Note(i.channel, i, i.velocity, i.time, Time(overallTime, tpb, bpm))] + except AttributeError: + pass + if "note_on" in str(i) and i.channel == 9: + if "note_on" in str(i) and i.velocity > 0: + print(i) + # print(i.note) + # print([Note(i.channel, i.note, i.velocity, i.time, Time(overallTime, tpb, bpm), -1)]) + tracks.append( + [ + Note( + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + -1, + ) + ] + ) + note_list.append( + [ + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + -1, + ] + ) + on.append([i.note, Time(overallTime, tpb, bpm)]) + isPercussion = True + # return [Note(i.channel, i, i.velocity, i.time, Time(overallTime, tpb, bpm))] + Notes.append(tracks) + if instruments is []: + instruments.append(0) + instruments = list(set(instruments)) + with open("1.pkl", "wb") as b: + pickle.dump([instruments, isPercussion], b) + + # for j, track in enumerate(mid.tracks): + # th = NewThread(loadMidi, (track,)) + # th.start() + # Notes.append(th.getResult()) + + # print(Notes) + print(Notes.__len__()) + # print(note_list) + print(instruments) + return Notes + # return [Notes, note_list] + + +def midiClassReader(midfile: str): + import mido + + from bgArrayLib.bpm import get + + def Time(mt, tpb_a, bpm_a): + return round(mt / tpb_a / bpm_a * 60 * 20) + + Notes = [] + tracks = [] + try: + mid = mido.MidiFile(filename=midfile, clip=True) + except Exception: + print("找不到文件或无法读取文件" + midfile) + return False + print("midi已经载入了。") + tpb = mid.ticks_per_beat + bpm = get(mid) + for track in mid.tracks: + overallTime = 0.0 + instrument = 0 + for i in track: + overallTime += i.time + if "note_on" in str(i) and i.velocity > 0: + print(i) + tracks.append( + [ + Note( + i.channel, + i.note, + i.velocity, + i.time, + Time(overallTime, tpb, bpm), + instrument, + ) + ] + ) + Notes.append(tracks) + print(Notes.__len__()) + return Notes diff --git a/old-things/bgArrayLib/sy_resourcesPacker.py b/old-things/bgArrayLib/sy_resourcesPacker.py new file mode 100644 index 0000000..1ec1bc3 --- /dev/null +++ b/old-things/bgArrayLib/sy_resourcesPacker.py @@ -0,0 +1,147 @@ +import os +import pickle +import shutil + +# import tkinter.filedialog +# from namesConstant import zip_name +# from namesConstant import mcpack_name +import bgArrayLib.namesConstant + +zipN = bgArrayLib.namesConstant.zip_name +mpN = bgArrayLib.namesConstant.mcpack_name + +manifest = { + "format_version": 1, + "header": { + "name": "羽音缭绕-midiout_25.5--音创使用", + "description": "羽音缭绕-midiout_25.0--音创使用", + "uuid": "c1adbda4-3b3e-4e5b-a57e-cde8ac80ee19", + "version": [25, 5, 0], + }, + "modules": [ + { + "description": "羽音缭绕-midiout_25.0--音创使用", + "type": "resources", + "uuid": "c13455d5-b9f3-47f2-9706-c05ad86b3180 ", + "version": [25, 5, 0], + } + ], +} + + +def resources_pathSetting(newPath: str = ""): + if not os.path.isfile("./bgArrayLib/resourcesPath.rpposi") and newPath == "": + return [False, 1] # 1:没有路径文件 + elif newPath != "": # not os.path.isfile("./bgArrayLib/resourcesPath.rpposi") and + path = newPath + print(path) + with open("./bgArrayLib/resourcesPath.rpposi", "w") as w: + w.write(path) + if "mcpack(国际版推荐)格式_25.0" in os.listdir( + path + ) and "zip格式_25.0" in os.listdir(path): + return [True, path, 1] # 1:都有 + elif "mcpack(国际版推荐)格式_25.0" in os.listdir( + path + ) and "zip格式_25.0" not in os.listdir(path): + return [True, path, 2] # 2:有pack + elif "mcpack(国际版推荐)格式_25.0" not in os.listdir( + path + ) and "zip格式_25.0" in os.listdir(path): + return [True, path, 3] # 3:有zip + else: + return [False, 2] # 2:路径文件指示错误 + if os.path.isfile("./bgArrayLib/resourcesPath.rpposi") and newPath == "": + with open("./bgArrayLib/resourcesPath.rpposi", "r") as f: + path = f.read() + if "mcpack(国际版推荐)格式_25.0" in os.listdir( + path + ) and "zip格式_25.0" in os.listdir(path): + return [True, path, 1] # 1:都有 + elif "mcpack(国际版推荐)格式_25.0" in os.listdir( + path + ) and "zip格式_25.0" not in os.listdir(path): + return [True, path, 2] # 2:有pack + elif "mcpack(国际版推荐)格式_25.0" not in os.listdir( + path + ) and "zip格式_25.0" in os.listdir(path): + return [True, path, 3] # 3:有zip + else: + return [False, 2] # 2:路径文件指示错误 + + raise + + +def choose_resources(): + global zipN + global mpN + back_list = [] + try: + with open(r"1.pkl", "rb") as rb: + instrument = list(pickle.load(rb)) + print(instrument) + except FileNotFoundError: + with open(r"./nmcsup/1.pkl", "rb") as rb: + instrument = list(pickle.load(rb)) + print(instrument) + path = resources_pathSetting() + if path.__len__() == 2: + return path + else: + dataT = path[2] + pathT = path[1] + if dataT == 1: + if instrument[1] is True: # 是否存在打击乐器 + index = zipN.get(-1, "") + percussion_instrument = str(pathT) + "\\zip格式_25.0\\" + index + # print(percussion_instrument) + back_list.append(percussion_instrument) + for i in instrument[0]: + ins_p = str(pathT) + "\\zip格式_25.0\\" + str(zipN.get(i)) + # print(ins_p) + back_list.append(ins_p) + print(back_list) + return back_list + elif dataT == 2: + if instrument[1] is True: + index = mpN.get(-1, "") + percussion_instrument = ( + str(pathT) + "\\mcpack(国际版推荐)格式_25.0\\" + index + ) + # print(percussion_instrument) + back_list.append(percussion_instrument) + for i in instrument[0]: + ins_p = str(pathT) + "\\mcpack(国际版推荐)格式_25.0\\" + str(mpN.get(i)) + # print(ins_p) + back_list.append(ins_p) + print(back_list) + return back_list + elif dataT == 3: + if instrument[1] is True: + index = zipN.get(-1, "") + percussion_instrument = str(pathT) + "\\zip格式_25.0\\" + index + # print(percussion_instrument) + back_list.append(percussion_instrument) + for i in instrument[0]: + ins_p = str(pathT) + "\\zip格式_25.0\\" + str(zipN.get(i)) + # print(ins_p) + back_list.append(ins_p) + print(back_list) + return back_list + raise + + +def scatteredPack(path): + pack_list = choose_resources() + print(pack_list) + print(path) + # os.close("L:/0WorldMusicCreater-MFMS new edition") + # shutil.copy("L:\\shenyu\\音源的资源包\\羽音缭绕-midiout_25.0\\mcpack(国际版推荐)格式_25.0\\0.Acoustic_Grand_Piano_大钢琴.mcpack", + # "L:/0WorldMusicCreater-MFMS new edition") + for i in pack_list: + shutil.copy(i, path) + + +if __name__ == "__main__": + # print(resources_pathSetting(r"L:\shenyu\音源的资源包\羽音缭绕-midiout_25.0")) + choose_resources() diff --git a/example.py b/old-things/example.py similarity index 100% rename from example.py rename to old-things/example.py diff --git a/example_futureFunction.py b/old-things/example_futureFunction.py similarity index 100% rename from example_futureFunction.py rename to old-things/example_futureFunction.py diff --git a/example_singleConvert.py b/old-things/example_singleConvert.py similarity index 100% rename from example_singleConvert.py rename to old-things/example_singleConvert.py diff --git a/example_websocket.py b/old-things/example_websocket.py similarity index 100% rename from example_websocket.py rename to old-things/example_websocket.py diff --git a/old-things/fcwslib/LICENSE b/old-things/fcwslib/LICENSE new file mode 100644 index 0000000..1c194c6 --- /dev/null +++ b/old-things/fcwslib/LICENSE @@ -0,0 +1 @@ +SEE: https://mingfengpigeon.mit-license.org/ \ No newline at end of file diff --git a/old-things/fcwslib/__init__.py b/old-things/fcwslib/__init__.py new file mode 100644 index 0000000..8e1c307 --- /dev/null +++ b/old-things/fcwslib/__init__.py @@ -0,0 +1,5 @@ +__all__ = ['Server', 'Plugin', 'build_header'] +__version__ = '3.0.1' +__author__ = ['mingfengpigeon ',"Eilles Wan "] + +from .server import Server, Plugin, build_header diff --git a/old-things/fcwslib/server.py b/old-things/fcwslib/server.py new file mode 100644 index 0000000..3620498 --- /dev/null +++ b/old-things/fcwslib/server.py @@ -0,0 +1,142 @@ +import asyncio +import copy +import json +import uuid + +import websockets + + +class Server: + sent_commands = {} + subscribed_events = {} + _plugins = [] + _connections = [] + + def __init__(self, server='0.0.0.0', port=8000, debug_mode=False): + self._server = server + self._port = port + self._debug_mode = debug_mode + + def handler(self): + return copy.deepcopy(self._plugins) + + def add_plugin(self, plugin): + if self._plugins: + for connection in self._connections: + plugin_ = plugin() + asyncio.create_task(plugin_.on_connect()) + connection.append(plugin_) + self._plugins.append(plugin) + + def remove_plugin(self, plugin): + if self._connections: + for connection in self._connections: + for plugin_ in connection.plugins: + if isinstance(plugin_, plugin): + plugin_.remove(plugin_) + break + self._plugins.remove(plugin) + + async def run_forever(self): + self.running = True + async with websockets.serve(self._on_connect, self._server, self._port): + await asyncio.Future() + + async def _on_connect(self, websocket, path): + plugins = [] + self._connections.append({ + "websocket": websocket, + "path": path, + "plugins": plugins, + }) + for plugin in self._plugins: + plugins.append(plugin(websocket, path, self, self._debug_mode)) + for plugin in plugins: + asyncio.create_task(plugin.on_connect()) + while self.running: + try: + response = json.loads(await websocket.recv()) + except (websockets.exceptions.ConnectionClosedOK, websockets.exceptions.ConnectionClosedError): + tasks = [] + for plugin in plugins: + tasks.append(plugin.on_disconnect()) + for task in tasks: + await task + break + else: + message_purpose = response['header']['messagePurpose'] + if message_purpose == 'commandResponse': + request_id = response['header']['requestId'] + if request_id in self.sent_commands: + asyncio.create_task(self.sent_commands[request_id](response)) + del self.sent_commands[request_id] + else: + try: + event_name = response['header']['eventName'] + asyncio.create_task(self.subscribed_events[event_name](response)) + except KeyError: + print("ERROR EVENT NAME:\n{}".format(response)) + + async def disconnect(self, websocket: websockets.WebSocketServerProtocol): + self.running = False + await websocket.close_connection() + for number in range(len(self._connections) - 1): + connection = self._connections[number] + if connection['websocket'] == websocket: + del self._connections[number] + + +class Plugin: + def __init__(self, websocket, path, server, debug_mode=False): + self._websocket = websocket + self._path = path + self._server = server + self._debug_mode = debug_mode + + async def on_connect(self): + pass + + async def on_disconnect(self): + pass + + async def on_receive(self, response): + pass + + async def send_command(self, command, callback=None): + request = { + 'body': {'commandLine': command}, + 'header': build_header('commandRequest') + } + if callback: + self._server.sent_commands[request['header']['requestId']] = callback + await self._websocket.send(json.dumps(request, **{'indent': 4} if self._debug_mode else {})) + + async def subscribe(self, event_name, callback): + request = { + 'body': {'eventName': event_name}, + 'header': build_header('subscribe') + } + self._server.subscribed_events[event_name] = callback + await self._websocket.send(json.dumps(request, **{'indent': 4} if self._debug_mode else {})) + + async def unsubscribe(self, event_name): + request = { + 'body': {'eventName': event_name}, + 'header': build_header('unsubscribe') + } + del self._server.subscribed_events[event_name] + await self._websocket.send(json.dumps(request, **{'indent': 4} if self._debug_mode else {})) + + async def disconnect(self): + await self._server.disconnect(self._websocket) + + +def build_header(message_purpose, request_id=None): + if not request_id: + request_id = str(uuid.uuid4()) + return { + 'requestId': request_id, + 'messagePurpose': message_purpose, + 'version': '1', + 'messageType': 'commandRequest', + } diff --git a/let_future_java.py b/old-things/let_future_java.py similarity index 100% rename from let_future_java.py rename to old-things/let_future_java.py diff --git a/test_fsq_opera.py b/old-things/test_fsq_opera.py similarity index 100% rename from test_fsq_opera.py rename to old-things/test_fsq_opera.py diff --git a/test_future_kamires.py b/old-things/test_future_kamires.py similarity index 100% rename from test_future_kamires.py rename to old-things/test_future_kamires.py diff --git a/test_future_lyric.py b/old-things/test_future_lyric.py similarity index 100% rename from test_future_lyric.py rename to old-things/test_future_lyric.py diff --git a/test_msq_opera.py b/old-things/test_msq_opera.py similarity index 100% rename from test_msq_opera.py rename to old-things/test_msq_opera.py diff --git a/pyproject.toml b/pyproject.toml index 21f7052..bfcb4b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ requires-python = ">= 3.8, < 4.0" dependencies = [ "mido >= 1.3", - "tomli>=2.4.0; python_version < '3.11'", - "tomli-w>=1.0.0", + "tomli >= 2.4.0; python_version < '3.11'", + "tomli-w >= 1.0.0", "xxhash >= 3", ] diff --git a/resources/msctDevAuthors.txt b/resources/msctDevAuthors.txt deleted file mode 100644 index a38f893..0000000 --- a/resources/msctDevAuthors.txt +++ /dev/null @@ -1,21 +0,0 @@ -# 注意,这里是作者署名文件,文件格式开头为单子启 -# 紧跟其后,不加空格留下常用名,常用名即常用网名 -# 而在其后是各个语言下的名字。用 井字符 开头表示 -# 注释,请注意,注释符号必须在一行之首否则无作用 -# 每进行一次分段表示一个新的开发者,换行表示一个 -# 新的语言。请全体开发者就此署名,谢谢! -启金羿 -zh-CN 金羿 -zh-TW 金羿 -zh-ME 金羿羿喵 -zh-HK 金 羿 -en-GB Eilles -en-US EillesWan - -启诸葛亮与八卦阵 -zh-CN 诸葛亮与八卦阵 -zh-TW 諸葛亮與八卦陣 -zh-ME 诸葛八卦喵 -zh-HK 諸葛亮與八卦陣 -en-GB Bagua Array -en-US bgArray \ No newline at end of file diff --git a/resources/poem.txt b/resources/poem.txt deleted file mode 100644 index f3a40d9..0000000 --- a/resources/poem.txt +++ /dev/null @@ -1,47 +0,0 @@ -> 是谁把科技的领域布满政治的火药 -> -> 是谁把纯净的蓝天染上暗淡的沉灰 -> -> 中国人民无不热爱自己伟大的祖国 -> -> 我们不会忘记屈辱历史留下的惨痛 -> -> 我们希望世界和平 -> -> 我们希望获得世界的尊重 -> -> 愿世上再也没有战争 -> -> 无论是热还是冷 -> -> 无论是经济还是政治 -> -> 让美妙的和平的优雅的音乐响彻世界 -> -> ——金羿 -> 2022 5 7 - - - -> Who has dropped political gunpowder into the technology -> -> Who has dyed clear blue sky into the dark grey -> -> All Chinese people love our great homeland -> -> We *WILL* remember the remain pain of the humiliating history -> -> We love the whole world but in peace -> -> We love everyone but under respect -> -> It is to be hoped that the war ends forever -> -> Whatever it is cold or hot -> -> Whatever it is economical or political -> -> Just let the wonderful music of peace surround the world -> -> ---- Eilles -> 7/5 2022 \ No newline at end of file diff --git a/tests/genexpr_vs_yieldfrom.py b/resources/test/genexpr_vs_yieldfrom.py similarity index 100% rename from tests/genexpr_vs_yieldfrom.py rename to resources/test/genexpr_vs_yieldfrom.py diff --git a/resources/音乐测试片段版权声明.txt b/resources/音乐测试片段版权声明.txt index 072f506..f3b1832 100644 --- a/resources/音乐测试片段版权声明.txt +++ b/resources/音乐测试片段版权声明.txt @@ -11,4 +11,4 @@ 不得用于商业用途 若 音·创 库被用于商业用途,应当将其剔除 -版权所有 © 2025 诸葛亮与八卦阵 \ No newline at end of file +版权所有 © 2026 玉衡Alioth \ No newline at end of file diff --git a/test_read.py b/test_read.py new file mode 100644 index 0000000..298bf30 --- /dev/null +++ b/test_read.py @@ -0,0 +1,18 @@ + +# 一个简单的项目实践测试 +from pathlib import Path +from Musicreater import load_plugin_module, MusiCreater +from Musicreater.plugins import _global_plugin_registry + +load_plugin_module("Musicreater.builtin_plugins.midi_read") + +print("当前支持的导入格式:", _global_plugin_registry.supported_input_formats()) +print("当前支持的导出格式:", _global_plugin_registry.supported_output_formats()) + +print(msct:=MusiCreater.import_music(Path("./resources/测试片段.mid"))) + +print(msct.music) + + + +print(msct.midi_2_music_plugin.load(Path("./resources/测试片段.mid"), None)) \ No newline at end of file