Musicreater/docs/库的生成与功能文档.md

290 lines
16 KiB
Python
Raw Normal View History

2023-01-06 04:32:18 +00:00
<h1 align="center">· Musicreater</h1>
<h2 align="center">库版 Package Version</h2>
<p align="center">
<img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png" >
</p>
2023-01-19 17:03:59 +00:00
**此为开发相关文档内容包括所生成文件结构的详细说明特殊参数的详细解释**
2023-01-06 04:32:18 +00:00
# 库的简单调用
参见[example.py的相关部分](../example.py)使用此库进行MIDI转换非常简单
- 在导入转换库后使用 MidiConvert 类建立转换对象读取Midi文件
·创库支持新旧两种execute语法需要在对象实例化时指定
```python
# 导入音·创库
import Musicreater
# 指定是否使用旧的execute指令语法即1.18及以前的《我的世界:基岩版》语法)
old_execute_format = False
# 可以通过文件地址自动读取
cvt_mid = Musicreater.MidiConvert.from_midi_file(
"Midi文件地址",
old_exe_format=old_execute_format
)
# 也可以导入Mido对象
cvt_mid = Musicreater.MidiConvert(
mido.MidiFile("Midi文件地址"),
"音乐名称",
old_exe_format=old_execute_format
)
```
- 获取 Midi 音乐经转换后的播放指令
```python
# 通过函数 to_command_list_in_score, to_command_list_in_delay
# 分别可以得到
# 以计分板作为播放器的指令对象列表、以延迟作为播放器的指令对象列表
# 数据不仅存储在对象本身内,也会以返回值的形式返回,详见代码内文档
# 使用 to_command_list_in_score 函数进行转换之后,返回值有三个
# 值得注意的是第一个返回值返回的是依照midi频道存储的指令对象列表
# 也就是列表套列表
# 但是,在对象内部所存储的数据却不会如此嵌套
command_channel_list, command_count, max_score = cvt_mid.to_command_list_in_score(
"计分板名称",
1.0, # 音量比率
1.0, # 速度倍率
)
# 使用 to_command_list_in_delay 转换后的返回值只有两个
# 但是第一个返回值没有列表套列表
command_list, max_delay = cvt_mid.to_command_list_in_delay(
1.0, # 音量比率
1.0, # 速度倍率
"@a", # 玩家选择器
)
# 运行之后,指令和总延迟会存储至对象内
print(
"音乐长度:{}/游戏刻".format(
cvt_mid.music_tick_num
)
)
print(
"指令如下:\n{}".format(
cvt_mid.music_command_list
)
)
```
- 除了获取播放指令外还可以获取进度条指令
```python
# 通过函数 form_progress_bar 可以获得
# 以计分板为载体所生成的进度条的指令对象列表
# 数据不仅存储在对象本身内,也会以返回值的形式返回,详见代码内文档
# 使用 form_progress_bar 函数进行转换之后,返回值有三个
# 值得注意的是第一个返回值返回的是依照midi频道存储的指令对象列表
# 也就是列表套列表
cvt_mid.form_progress_bar(
max_score, # 音乐时长游戏刻
scoreboard_name, # 进度条使用的计分板名称
progressbar_style, # 进度条样式组(详见下方)
)
# 同上面生成播放指令的理,进度条指令也混存储至对象内
print(
"进度条指令如下:\n{}".format(
cvt_mid.progress_bar_command
)
)
```
在上面的代码中进度条样式是可以自定义的详见[下方说明](%E5%BA%93%E7%9A%84%E7%94%9F%E6%88%90%E4%B8%8E%E5%8A%9F%E8%83%BD%E6%96%87%E6%A1%A3.md#进度条自定义)。
- 转换成指令是一个方面接下来是再转换为可以导入MC的格式
***诶哟我好累不想写了等有时间再写你们就看样例程序的用法吧无量天尊***
***这后面一直到下一个小节的内容全是没改的旧内容肯定有问题***
```python
# 设置输入输出地址并指定execute指令语法
# 地址都为字符串类型,不能传入文件流
midi_path = "./where/you/place/.midi/files.mid"
output_folder = "./where/you/want2/convert/into/"
2023-03-11 10:23:40 +00:00
# 设定基本转换参数
conversion.convert(midi_path,output_folder)
2023-03-11 10:23:40 +00:00
# 进行转换并接受输出,具体的参数均在代码之文档中有相关说明
method_id = 3 # 指定使用的转换算法
# 使用计分板播放器,转换为附加包文件
convertion_result = conversion.to_mcpack(method_id,*prompts)
# 使用延迟播放器,转换为附加包文件
# 注意,在执行这个功能之前,你需要使用指令
# pip install TrimMCStruct
# 安装最新版的TrimMCStruct库
convertion_result = conversion.to_mcpack_with_delay(method_id,*prompts)
2023-03-11 10:23:40 +00:00
# 使用计分板播放器转换为BDX结构文件
convertion_result = conversion.to_BDX_file(method_id,*prompts)
# 使用延迟播放器转换为BDX结构文件
convertion_result = conversion.to_BDX_file_with_delay(method_id,*prompts)
# 转换结果是一个元组。
# 若其转换成功,则前二位必为
# True, 指令数量, 最大延迟
# 其中,最大延迟可以理解为计分板的最大值
# 如果转换失败,暂时还没有定返回值的规则
# 但是有一点是肯定的,数据结构必定是元组
print(convertion_result)
```
2023-01-19 17:03:59 +00:00
# 生成文件结构
2023-01-06 04:32:18 +00:00
## 名词解释
|名词|解释|备注|
|--------|-----------|----------|
|指令区|一个用于放置指令系统的区域通常是常加载区|常见于服务器指令系统好友联机房间中|
|指令链|与链式指令方块不同一个指令链通常指代的是一串由某种非链式指令方块作为开头后面连着一串链式指令方块的结构|通常的链都应用于需要单次激活而多指令的简单功能|
|起始块|链最初的那个非链式指令方块|此方块为脉冲方块或重复方块皆可|
|指令系统系统|指令系统通常指的是由一个或多个指令链以及相关红石机构相互配合一同组成的为达到某种特定的功能而构建的整体结构|通常的系统都应用于需要综合调配指令的复杂功能可由多个实现不同功能的模块构成不同系统之间可以相互调用各自的模块|
|游戏刻|游戏的一刻是指我的世界的游戏循环运行一次所占用的时间[详见我的世界中文维基](https://minecraft.fandom.com/zh/wiki/%E5%88%BB#%E6%B8%B8%E6%88%8F%E5%88%BB))。指令方块的延迟功能(即指令方块的“延迟刻数”设置项,此项的名称被误译为“已选中项的延迟”)的单位即为`1`游戏刻。|正常情况下游戏固定以每秒钟20刻的速率运行。但是由于游戏内的绝大多数操作都是基于刻数而非现实中的时间来计时并进行的一次游戏循环内也许会发生大量的操作很多情况下一秒对应的游戏刻会更少。 |
## 文件格式
1. 附加包格式`.mcpack`
使用附加包格式导出音乐则音乐会以指令函数文件`.mcfunction`存储于附加包内在附加包中函数文件的存储结构应为
- `functions\`
- `index.mcfunction`
- `mscply\`
- `progressShow.mcfunction`
- `track1.mcfunction`
- `track2.mcfunction`
- ...
- `trackN.mcfunction`
如图其中`index.mcfunction`文件和`mscply`文件夹存在于函数目录的根下`mscply`目录中包含音乐导出的众多音轨播放文件`trackX.mcfunction`同时若生成此包时选择了带有进度条的选项则会包含`progressShow.mcfunction`文件
`index.mcfunction`用于开始播放其中包含打开各个音轨对应函数的指令以及加分指令这里的加分是将**播放计分板的值大于等于`1`**的所有**玩家**的播放计分板分数增加`1`同时若生成此包时选择了自动重置计分板的选项则会包含一条重置计分板的指令
> 你知道吗·创的最早期版本我的世界函数音乐生成器正是用函数来播放不过这个版本采取的读入数据的形式大有不同
2. 结构格式
无论是音·创生成的是何种结构`MCSTRUCTURE`还是`BDX`都会依照此处的格式来生成此处我们想说明的结构的格式不是结构文件存储的格式而是结构导出之后方块将如何摆放的问题结构文件存储的格式这一点在各个我的世界开发的相关网站上都可能会有说明
考虑到进行我的世界游戏开发时为了节约常加载区域很多游戏会将指令区设立为一种层叠式的结构这种结构会限制每一层的指令系统的高度但是虽然长宽也是有限的却仍然比其纵轴延伸得更加自由
所以结构的生成形状依照给定的高度和内含指令的数量决定 $Z$ 轴延伸长度为指令方块数量对于给定高度之商的向下取整结果的平方根的向下取整用数学公式的方式表达则是
2023-01-06 04:32:18 +00:00
$$ MaxZ = \left\lfloor\sqrt{\left\lfloor{\frac{NoC}{MaxH}}\right\rfloor}\right\rfloor $$
2023-01-06 04:32:18 +00:00
其中$MaxZ$ 即生成结构的$Z$轴最大延伸长度$NoC$ 表示链结构中所含指令方块的个数$MaxH$ 表示给定的生成结构的最大高度
2023-01-06 04:32:18 +00:00
我们的结构生成器在生成指令链时将首先以相对坐标系 $(0, 0, 0)$ 即相对原点开始自下向上堆叠高度轴 $Y$ 的长当高度轴达到了限制的高度时便将 $Z$ 轴向正方向堆叠`1`个方块并开始自上向下重新堆叠直至高度轴坐标达到相对为 `0`若当所生成结构的 $Z$ 轴长达到了其最大延伸长度则此结构生成器将反转 $Z$ 轴的堆叠方向直至 $Z$ 轴坐标相对为 `0`如此往复直至指令链堆叠完成
2023-01-06 04:32:18 +00:00
## 播放器
以结构生成的文件可以采用多种方式播放一类播放方式我们称其为**播放器**例如**延迟播放器****计分板播放器**等等以后推出的新的播放器届时也会在此处更新
为什么要设计这么多播放器是为了适应不同的播放环境需要通常情况下一个音乐中含有多个音符音符与音符之间存在间隔这里就产生了不一样的实现音符间时间间隔的方式而不同的应用环境下又会产生不一样的要求接下来将对不同的播放器进行详细介绍
1. 计分板播放器
计分板播放器是一种传统的我的世界音乐播放方式通过对于计分板加分来实现播放不同的音符一个很简单的原理就是**用不同的计分板分值对应不同的音符**再通过加分来达到那个分值即播放出来
**·**用来达到这种效果的指令是这样的
```mcfunction
execute @a[scores={ScBd=x}] ~ ~ ~ playsound InstID @s ~ ~Ht ~ Vlct Ptc
```
|参数|说明|备注|
|--------|-----------|----------|
|`ScBd`|指定的计分板名称||
|`x`|音发出时对应的分数值||
|`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)|
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ |
2023-01-06 04:32:18 +00:00
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号 $x$ 表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
2023-01-06 04:32:18 +00:00
后四个参数决定了这个音的性质而前两个参数仅仅是为了决定音播放的时间
2. 延迟播放器
延迟播放器是通过我的世界游戏中指令方块的设置项延迟刻数来达到定位音符的效果**将所有的音符依照其播放时距离乐曲开始时的时间毫秒放在一个序列内再计算音符两两之间对应的时间差值转换为我的世界内对应的游戏刻数之后填入指令方块的设置中**
在音·创中由于此方式播放的音乐不需要用计分板所以播放指令是这样的
```mcfunction
execute Tg ~ ~ ~ playsound InstID @s ~ ~Ht ~ Vlct Ptc
```
|参数|说明|备注|
|--------|-----------|----------|
|`Tg`|播放对象|选择器或玩家名|
|`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)|
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ |
2023-01-06 04:32:18 +00:00
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号$x$表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
2023-01-06 04:32:18 +00:00
其中后四个参数决定了这个音的性质
2023-01-19 17:03:59 +00:00
由于这样的延迟数据是依赖于指令方块的设置项所以使用这种播放器所转换出的结果仅可以存储在包含方块NBT信息及方块实体NBT信息的结构文件中或者直接输出至世界
# 进度条自定义
因为我们提供了可以自动转换进度条的功能因此在这里给出进度条自定义参数的详细解释
请注意并非所有的演示样例程序都支持自定义进度条
一个进度条明显地**固定部分****可变部分**来构成而可变部分又包括了文字和图形两种当然我的世界里头的进度条可变的图形也就是那个这一点你需要了解因为后文中包含了很多这方面的概念需要你了解
进度条的自定义功能使用一个字符串来定义自己的样式其中包含众多**标识符**来表示可变部分
标识符如下注意大小写
| 标识符 | 指定的可变量 |
|---------|----------------|
| `%%N` | 乐曲名(即传入的文件名)|
| `%%s` | 当前计分板值 |
| `%^s` | 计分板最大值 |
| `%%t` | 当前播放时间 |
| `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位|
表示进度条占位的 `_` 是用来标识你的进度条的也就是可变部分的唯一的图形部分
**样式定义字符串**的样例如下这也是默认的进度条的样式
` %%N [ %%s/%^s %%% __________ %%t|%^t]`
这是单独一行的进度条当然你也可以制作多行的如果是一行的输出时所使用的指令便是 `title`而如果是多行的话输出就会用 `titleraw` 作为进度条字幕
哦对了上面的只不过是样式定义同时还需要定义的是可变图形的部分也就是进度条上那个真正的
对于这个我们就采用了固定参数的方法对于一个进度条无非就是已经播放过的没播放过的两种形态所以使用一个元组来传入这两个参数就是最简单的了元组的格式也很简单`(str: 播放过的部分长啥样, str: 没播放过的部分长啥样)` 例如我们默认的进度的定义是这样的
`('§e=§r', '§7=§r')`
综合起来把这些参数传给函数需要一个参数整合你猜用的啥啊对对对我用的还是元组
我们的默认定义参数如下
`(r'%%N [ %%s/%^s %%% __________ %%t|%^t]',('§e=§r', '§7=§r'))`
*为了避免生成错误请尽量避免使用标识符作为定义样式字符串的其他部分*
2023-01-19 17:03:59 +00:00