合并双机器工作之变化性更改

This commit is contained in:
EillesWan 2025-05-26 17:33:39 +08:00
parent 7a1ca86132
commit b65483b32d
11 changed files with 307 additions and 72 deletions

View File

@ -1,6 +1,6 @@
# 汉钰律许可协议
# 汉钰律许可协议,第一版
**总第一版 · 二〇二四年七月七日编**
**总第一版 第二次修订 · 二〇二四年七月七日编 二〇二五年四月二十六日修订**
## 一、重要须知
@ -12,13 +12,13 @@
4. 由于互联网服务互联网内容的特殊性若本协议以电子协议形式分发并签订其依然有效您一旦开始对本协议所授权之作品进行本协议所授权的行为即视为您已经阅读理解并同意并已经接受本协议的全部条款
5. 本协议的订立履行解释及争议的解决均**适用中华人民共和国法律并排除其他一切冲突法的适用**_本协议订立于许可证最初的颁发者的地址为自然人则订立于该自然人户籍所在地若为法人或非法人组织则订立于其注册地_本协议的订立各方应友好协商解决于协议所规定之行为的履行相关的争议如协商不成任何一方均可向合同签订地有管辖权的人民法院提起诉讼
5. 本协议的订立履行解释及争议的解决均**适用中华人民共和国法律并排除其他一切冲突法的适用**_本协议订立于许可证最初的颁发者的地址颁发者为自然人则订立于该自然人户籍所在地若为法人或非法人组织则订立于其注册地_本协议的订立各方应友好协商解决于协议所规定之行为的履行相关的争议如协商不成任何一方均可向合同签订地有管辖权的人民法院提起诉讼
6. 本协议的原本仅为现代汉语书写于简体中文若存在其他语言的翻译或其他同等语言但非简体中文文本的版本应当无法律效力
## 二、术语定义
1. **许可证****协议**后文称本协议是指根据本文档中所列举的全部术语定义条款限制等文本是本合同的简称称谓本合同全称是汉钰律许可协议
1. **许可证****协议**后文称本协议是指根据本文档中所列举的全部术语定义条款限制等文本是本合同的简称称谓本合同全称是 **汉钰律许可协议第一版**
2. **协议颁发者**后文称颁发者是将条款或协议应用于其拥有著作财产权的作品的民事主体或由其指定从而拥有颁发者身份的民事主体
@ -28,13 +28,13 @@
5. **采用本协议的作品**后文称此作品是指经颁发者授权而使用本协议进行授权的任何作品该作品应在自然人可见处明确附加一个自然人可读的版权通知可以参考文末附录中提供的示例若在一个可分割的作品中部分地采用本协议进行授权则该部分应当视为一个独立的采用本协议的作品该作品应当在自然人可见处明确附加一个自然人可读的范围限定和版权通知同样可以参考文末附录中提供的示例
6. **贡献**是指对作品进行的意在提交给此作品颁发者以让著作权人包含在其作品中的任何修订或补充该修订或补充同样属于一种作品依据此定义提交一词表示经由此作品颁发者所指定的形式将其所进行的修改发送给此作品颁发者该形式应当包括在此作品颁发者指定的平台内发送易于编辑的修改信息在此作品颁发者指定的电子邮箱中发送易于编辑的修改信息在此作品颁发者指定的源码控制系统或发布跟踪系统上提交的易于编辑的修改信息但由著作权人以明显标注或指定为非贡献的活动除外颁发者自己对作品进行的修改同样视作对作品的贡献
6. **贡献**是指对作品进行的意在提交给此作品颁发者以让著作权人包含在其作品中的任何修订或补充该修订或补充同样属于一种作品依据此定义**提交**一词表示经由此作品颁发者所指定的形式将其所进行的修改发送给此作品颁发者该形式应当包括在此作品颁发者指定的平台内发送易于编辑的修改信息在此作品颁发者指定的电子邮箱中发送易于编辑的修改信息在此作品颁发者指定的源码控制系统或发布跟踪系统上提交的易于编辑的修改信息但由著作权人以明显标注或指定为非贡献的活动除外颁发者自己对作品进行的修改同样视作对作品的贡献
7. **贡献者**是指此作品颁发者接受的贡献的提交者或包含在作品的贡献清单中的民事主体贡献者在提交贡献并经此作品颁发者通过且该贡献已经被应用于此作品中后该贡献者应当视为此作品的著作权人之一但不应视为此作品非其贡献的部分的著作权人一个作品的颁发者同样属于其贡献者**请注意**针对贡献者提交的贡献该贡献者应被视为该贡献的协议颁发者但不应视作本作品的颁发者
8. **用户****使用者**是指行使本协议所授权之行为的民事主体据此贡献者亦属于用户
9. **商业性使用****商用**是指任何以谋取利益为目的的使用包括但不限于以贩卖出租的形式对作品进行使用但若将该牟利活动明确指示为捐赠且在牟利者进行本协议所授权的活动时不以捐赠数额为标准则此种的获取利益的捐赠行为不属于商业性使用
9. **商业性使用****商用**是指任何以谋取利益为目的的使用包括但不限于以贩卖出租的形式对作品进行使用但若将该获取利益之活动明确指示为捐赠且在获利者在进行本协议所授权的活动时不以捐赠数额为标准而区别之则此种的获取利益的捐赠行为不属于商业性使用
## 三、权利授予
@ -82,7 +82,7 @@
该通知的内容仅供信息提供不应对许可证进行任何文字上的修改用户可在其分发的作品中在不构成修改本协议的前提下在作品自身的声明通知或属性描述后或作为附录添加
6. 依据本款第3条若用户二次分发此作品时选择向作品的接收者提供收费的担保服务则必须明确告知该接收者本协议全部内容与此作品原出处并确保其知悉上述内容但若用户在二次分发此作品不选择提供任何服务则该用户不允许向作品的接收者收取任何费用除非该用户获得了此作品颁发者的特殊许可或该用户即为此作品颁发者本人
6. 依据本款第3条若用户二次分发此作品时选择向作品的接收者提供收费的担保服务则必须明确告知该接收者本协议全部内容与此作品原出处并确保其知悉上述内容但若用户在二次分发此作品不选择提供任何服务则该用户不允许向作品的接收者收取任何费用除非该用户获得了此作品颁发者的特殊许可或该用户即为此作品颁发者本人
## 五、提交贡献
@ -94,7 +94,7 @@
## 七、免责声明
1. 若非因法律要求或经过了特殊准许此作品在根据本协议原样提供的基础上**不予提供任何形式的担保任何明示任何暗示或类似承诺**此类包括但不限于担保此作品毫无缺陷担保此作品适于贩卖担保此作品适于特定目的担保使用此作品绝不侵权用户将自行承担因此作品的质量或性能问题而产生的全部风险若此作品在任何方面欠妥将由用户而非任何贡献者而非任何颁发者承担所有必要的服务维修或除错的任何成本本免责声明本许可的重要组成部分当且仅当遵守本免责声明时本协议的其他条款中对本作品的使用授权方可生效
1. 若非因法律要求或经过了特殊准许此作品在根据本协议原样提供的基础上**不予提供任何形式的担保任何明示任何暗示或类似承诺**此类包括但不限于担保此作品毫无缺陷担保此作品适于贩卖担保此作品适于特定目的担保使用此作品绝不侵权用户将自行承担因此作品的质量或性能问题而产生的全部风险若此作品在任何方面欠妥将由用户而非任何贡献者而非任何颁发者承担所有必要的服务维修或除错的任何成本本免责声明本许可的重要组成部分当且仅当遵守本免责声明时本协议的其他条款中对本作品的使用授权方可生效
2. 无论是因何种原因如果不是在法律规定的特殊情况确为贡献者的故意或重大过失下或者经过了特殊准许即使贡献者事先已知发生损害的可能在使用本作品时用户产生的任何直接间接特殊偶然或必然造成的损失包括但不限于商誉损失工作延误计算机系统故障等**均不由任一贡献者承担**
@ -116,7 +116,7 @@
版权所有 © 年份 著作权人
或者版权所有 (C) 年份 著作权人
该作品根据 第一版 汉钰律许可协议本协议授权
该作品根据 汉钰律许可协议第一版本协议授权
任何人皆可从以下地址获得本协议副本本协议副本所在地址
若非因法律要求或经过了特殊准许此作品在根据本协议原样提供的基础上不予提供任何形式的担保任何明示任何暗示或类似承诺也就是说用户将自行承担因此作品的质量或性能问题而产生的全部风险
详细的准许和限制条款请见原协议文本

View File

@ -49,6 +49,8 @@ __all__ = [
"MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE",
"MM_TOUCH_PITCHED_INSTRUMENT_TABLE",
"MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE",
"MM_DISLINK_PITCHED_INSTRUMENT_TABLE",
"MM_DISLINK_PERCUSSION_INSTRUMENT_TABLE",
"MM_NBS_PITCHED_INSTRUMENT_TABLE",
"MM_NBS_PERCUSSION_INSTRUMENT_TABLE",
# 操作性函数

View File

@ -16,19 +16,202 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import Dict, List, Tuple
from .exceptions import *
from .main import (
MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE,
MM_CLASSIC_PITCHED_INSTRUMENT_TABLE,
MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
MidiConvert,
mido,
)
from .subclass import *
from .types import ChannelType, Dict, List, Tuple
from .types import ChannelType, FittingFunctionType
from .utils import *
class FutureMidiConvertKamiRES(MidiConvert):
@staticmethod
def to_music_note_channels(
midi: mido.MidiFile,
ignore_mismatch_error: bool = True,
speed: float = 1.0,
default_program_value: int = -1,
default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
pitched_note_rtable: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
vol_processing_function: FittingFunctionType = natural_curve,
note_rtable_replacement: Dict[str, str] = {},
) -> Tuple[MineNoteChannelType, int, Dict[str, int]]:
"""
将midi解析并转换为频道音符字典
Parameters
----------
midi: mido.MidiFile 对象
需要处理的midi对象
speed: float
音乐播放速度倍数
default_program_value: int
默认的 MIDI 乐器值
default_tempo_value: int
默认的 MIDI TEMPO
pitched_note_rtable: Dict[int, Tuple[str, int]]
乐音乐器Midi-MC对照表
percussion_note_rtable: Dict[int, Tuple[str, int]]
打击乐器Midi-MC对照表
vol_processing_function: Callable[[float], float]
声像偏移拟合函数
note_rtable_replacement: Dict[str, str]
音符名称替换表此表用于对 Minecraft 乐器名称进行替换而非 Midi Program 的替换
Returns
-------
以频道作为分割的Midi音符列表字典, 音符总数, 乐器使用统计:
Tuple[MineNoteChannelType, int, Dict[str, int]]
"""
if speed == 0:
raise ZeroSpeedError("播放速度为 0 ,其需要(0,1]范围内的实数。")
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
midi_channels: MineNoteChannelType = empty_midi_channels(default_staff=[])
channel_program: Dict[int, int] = empty_midi_channels(
default_staff=default_program_value
)
tempo = default_tempo_value
note_count = 0
note_count_per_instrument: Dict[str, int] = {}
microseconds = 0
note_queue_A: Dict[
int,
List[
Tuple[
int,
int,
]
],
] = empty_midi_channels(default_staff=[])
note_queue_B: Dict[
int,
List[
Tuple[
int,
int,
]
],
] = empty_midi_channels(default_staff=[])
# 直接使用mido.midifiles.tracks.merge_tracks转为单轨
# 采用的时遍历信息思路
for msg in midi.merged_track:
if msg.time != 0:
# 微秒
microseconds += msg.time * tempo / midi.ticks_per_beat
# 简化
if msg.type == "set_tempo":
tempo = msg.tempo
else:
if msg.type == "program_change":
channel_program[msg.channel] = msg.program
elif msg.type == "note_on" and msg.velocity != 0:
note_queue_A[msg.channel].append(
(msg.note, channel_program[msg.channel])
)
note_queue_B[msg.channel].append((msg.velocity, microseconds))
elif (msg.type == "note_off") or (
msg.type == "note_on" and msg.velocity == 0
):
if (msg.note, channel_program[msg.channel]) in note_queue_A[
msg.channel
]:
_velocity, _ms = note_queue_B[msg.channel][
note_queue_A[msg.channel].index(
(msg.note, channel_program[msg.channel])
)
]
note_queue_A[msg.channel].remove(
(msg.note, channel_program[msg.channel])
)
note_queue_B[msg.channel].remove((_velocity, _ms))
midi_channels[msg.channel].append(
that_note := midi_msgs_to_minenote_using_kami_respack(
inst_=(
msg.note
if msg.channel == 9
else channel_program[msg.channel]
),
note_=(
channel_program[msg.channel]
if msg.channel == 9
else msg.note
),
percussive_=(msg.channel == 9),
velocity_=_velocity,
start_time_=_ms, # 微秒
duration_=microseconds - _ms, # 微秒
play_speed=speed,
midi_reference_table=(
percussion_note_rtable
if msg.channel == 9
else pitched_note_rtable
),
volume_processing_method_=vol_processing_function,
note_table_replacement=note_rtable_replacement,
)
)
note_count += 1
if that_note.sound_name in note_count_per_instrument.keys():
note_count_per_instrument[that_note.sound_name] += 1
else:
note_count_per_instrument[that_note.sound_name] = 1
else:
if ignore_mismatch_error:
print(
"[WARRING] MIDI格式错误 音符不匹配 {} 无法在上文中找到与之匹配的音符开音消息".format(
msg
)
)
else:
raise NoteOnOffMismatchError(
"当前的MIDI很可能有损坏之嫌……",
msg,
"无法在上文中找到与之匹配的音符开音消息。",
)
"""整合后的音乐通道格式
每个通道包括若干消息元素其中逃不过这三种
1 切换乐器消息
("PgmC", 切换后的乐器ID: int, 距离演奏开始的毫秒)
2 音符开始消息
("NoteS", 开始的音符ID, 力度响度, 距离演奏开始的毫秒)
3 音符结束消息
("NoteE", 结束的音符ID, 距离演奏开始的毫秒)"""
del tempo
channels = dict(
[
(channel_no, sorted(channel_notes, key=lambda note: note.start_tick))
for channel_no, channel_notes in midi_channels.items()
]
)
return (
channels,
note_count,
note_count_per_instrument,
)
class FutureMidiConvertJavaE(MidiConvert):
def form_java_progress_bar(

View File

@ -16,19 +16,10 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import (
Dict,
List,
Literal,
Tuple,
Union,
Mapping,
Callable,
)
from typing import Callable, Dict, List, Literal, Mapping, Tuple, Union
from .subclass import MineNote
MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
"""
Midi音符名称对照表类型

View File

@ -295,6 +295,68 @@ def midi_msgs_to_minenote(
)
def midi_msgs_to_minenote_using_kami_respack(
inst_: int, # 乐器编号
note_: int,
percussive_: bool, # 是否作为打击乐器启用
velocity_: int,
start_time_: int,
duration_: int,
play_speed: float,
midi_reference_table: MidiInstrumentTableType,
volume_processing_method_: Callable[[float], float],
note_table_replacement: Dict[str, str] = {},
) -> MineNote:
"""
将Midi信息转为我的世界音符对象
:param inst_: int 乐器编号
:param note_: int 音高编号音符编号
:param percussive_: bool 是否作为打击乐器启用
:param velocity_: int 力度(响度)
:param start_time_: int 音符起始时间微秒
:param duration_: int 音符持续时间微秒
:param play_speed: float 曲目播放速度
:param midi_reference_table: Dict[int, str] 转换对照表
:param volume_proccessing_method_: Callable[[float], float] 音量处理函数
:param note_table_replacement: Dict[str, str] 音符替换表定义 Minecraft 音符字串的替换
:return MineNote我的世界音符对象
"""
using_original = False
if not percussive_ and (0 <= inst_ <= 119):
mc_sound_ID = "{}{}.{}".format(
inst_, "d" if duration_ < 500_000 else "c", note_
)
elif percussive_ and (27 <= inst_ <= 87):
mc_sound_ID = "-1d.{}".format(inst_)
else:
using_original = True
mc_sound_ID = midi_inst_to_mc_sound(
inst_,
midi_reference_table,
"note.bd" if percussive_ else "note.flute",
)
mc_distance_volume = volume_processing_method_(velocity_)
return MineNote(
mc_sound_name=note_table_replacement.get(mc_sound_ID, mc_sound_ID),
midi_pitch=note_ if using_original else 1,
midi_velocity=velocity_,
start_time=(tk := int(start_time_ / float(play_speed) / 50000)),
last_time=round(duration_ / float(play_speed) / 50000),
mass_precision_time=round((start_time_ / float(play_speed) - tk * 50000) / 800),
is_percussion=percussive_,
displacement=(0, mc_distance_volume, 0),
extra_information={
"USING_ORIGINAL_SOUND": using_original, # 判断 extra_information 中是否有 USING_ORIGINAL_SOUND 键是判断是否使用神羽资源包解析的一个显著方法
"INST_VALUE": note_ if percussive_ else inst_,
"NOTE_VALUE": inst_ if percussive_ else note_,
},
)
# def single_note_to_minenote(
# note_: SingleNote,
# reference_table: MidiInstrumentTableType,

View File

@ -1,26 +1,23 @@
import Musicreater
import Musicreater.experiment
import Musicreater.previous
import Musicreater.plugin
# import Musicreater.previous
from Musicreater.plugin.addonpack import (
to_addon_pack_in_delay,
to_addon_pack_in_repeater,
to_addon_pack_in_score,
)
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
from Musicreater.plugin.mcstructfile import (
to_mcstructure_file_in_delay,
to_mcstructure_file_in_repeater,
to_mcstructure_file_in_score,
)
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
MSCT_MAIN = (
Musicreater,
Musicreater.experiment,
Musicreater.previous,
# Musicreater.previous,
)
MSCT_PLUGIN = (Musicreater.plugin,)
@ -38,8 +35,8 @@ MSCT_PLUGIN_FUNCTION = (
import hashlib
import dill
import brotli
import dill
def enpack_msct_pack(sth, to_dist: str):

View File

@ -3,8 +3,7 @@
[CodeStyle: black]: https://img.shields.io/badge/code%20style-black-121110.svg?style=for-the-badge
[python]: https://img.shields.io/badge/python-3.8-AB70FF?style=for-the-badge
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
[license]: https://img.shields.io/badge/Licence-%E6%B1%89%E9%92%B0%E5%BE%8B%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE-228B22?style=for-the-badge
<h1 align="center">· Musicreater </h1>

View File

@ -3,7 +3,7 @@
[CodeStyle: black]: https://img.shields.io/badge/code%20style-black-121110.svg?style=for-the-badge
[python]: https://img.shields.io/badge/python-3.8-AB70FF?style=for-the-badge
[release]: https://img.shields.io/github/v/release/EillesWan/Musicreater?style=for-the-badge
[license]: https://img.shields.io/badge/Licence-Apache-228B22?style=for-the-badge
[license]: https://img.shields.io/badge/Licence-%E6%B1%89%E9%92%B0%E5%BE%8B%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE-228B22?style=for-the-badge
<h1 align="center">
· Musicreater
@ -129,4 +129,3 @@ NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
Minecraft Mojang Synergies AB 的商标此项目中所有对于我的世界Minecraft等相关称呼均为必要的介绍性使用
- 上文提及的 网易 公司指代的是在中国大陆运营我的世界中国版的上海网之易璀璨网络科技有限公司

View File

@ -1,11 +1,11 @@
from rich.pretty import pprint
import Musicreater
from Musicreater.utils import (
load_decode_fsq_flush_release,
load_decode_musicsequence_metainfo,
)
from rich.pretty import pprint
msc_seq = Musicreater.MusicSequence.from_mido(
Musicreater.mido.MidiFile(
"./resources/测试片段.mid",

2
test_future_kamires.py Normal file
View File

@ -0,0 +1,2 @@
pass

View File

@ -1,11 +1,11 @@
from rich.pretty import pprint
import Musicreater
from Musicreater.utils import (
load_decode_msq_flush_release,
load_decode_musicsequence_metainfo,
)
from rich.pretty import pprint
msc_seq = Musicreater.MusicSequence.from_mido(
Musicreater.mido.MidiFile(
"./resources/测试片段.mid",