266 Commits

Author SHA1 Message Date
EillesWan
83c9750db3 重大更新:优化算法+红石指令音乐生成 2023-08-12 12:39:30 +08:00
EillesWan
5c86a28b44 okay 2023-07-31 23:25:45 +09:00
EillesWan
70674ec6f7 增加对于不正规Midi兼容性的支持,避免转换错误的情况发生。 2023-07-31 22:28:14 +09:00
EillesWan
f73c1be944 更高效的算法管理与兼容性和代码格式更新,详见样例代码;同时新增实验算法,在其中尝试下次更新的内容 2023-07-01 19:11:10 +08:00
EillesWan
36f8db722b Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-06-11 13:10:42 +08:00
EillesWan
bedb3924c6 新增一个感谢人 2023-06-11 13:10:39 +08:00
EillesWan
81ae7ae146 修复一些小问题 2023-06-11 13:09:11 +08:00
bgArray
c39c6c4488 Remove feudal superstition 2023-06-04 21:33:20 +08:00
EillesWan
556ce74cfb 修复打击乐器播放时的错误,即将步入红石音乐生成阶段 2023-06-04 17:01:59 +08:00
EillesWan
3da472052e 代码架构升级,功能分割,减少强制性依赖,API全新换代,文档全面更新,新一代音·创,音·创1.0.0 2023-05-27 18:41:02 +08:00
EillesWan
ffe5837c9f 不要更新!不要更新!命运的齿轮尚未开始转动,前方的道路将会铺满沙尘。 2023-05-07 19:25:51 +08:00
EillesWan
42e2fcdd98 要更新,要更新 2023-05-01 19:34:22 +08:00
EillesWan
755de846c7 小改example 2023-05-01 13:58:11 +08:00
EillesWan
cb95c51a47 修复重大问题:延迟播放器中音符的延迟过长,感谢Mono 2023-05-01 12:40:40 +08:00
bgArray
6fe8e41dfa update 2023/4/30 pypi update 2023-04-30 22:45:03 +08:00
EillesWan
b8bae7b913 你觉得我为什么还在用3.8 2023-04-30 22:05:43 +08:00
EillesWan
7663bf8838 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-04-30 21:57:40 +08:00
EillesWan
8aa503710d 紧急更新,修复安卓无法使用的小bug 2023-04-30 21:57:14 +08:00
bgArray
d5d7230537 update 2023/4/29 pypi update 2023-04-29 22:04:41 +08:00
EillesWan
5d48fcd96a Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-04-29 21:32:16 +08:00
EillesWan
aa94e3758b 更新一下版本 2023-04-29 21:32:09 +08:00
mingfengpigeon
8b06078a90 Format. 2023-04-29 21:28:36 +08:00
EillesWan
799b9b664d Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-04-29 17:00:36 +08:00
EillesWan
4874ace92d 史诗级更新!支持导出mcstructure库,更改部分API和文档,修改了部分代码格式,新增红乐测试 2023-04-29 17:00:32 +08:00
bgArray
54cd6b196e update 2023/4/19 pypi update2 2023-04-19 21:45:43 +08:00
bgArray
882fa4175e Merge remote-tracking branch 'origin/master' 2023-04-19 21:18:04 +08:00
bgArray
b15c89b6c8 update 2023/4/19 pypi update & v0.4.0 update 2023-04-19 21:17:51 +08:00
EillesWan
b758a2f967 更改依赖版本 2023-04-16 19:14:13 +08:00
EillesWan
a9ec7582a9 更新版本 2023-04-16 19:12:10 +08:00
EillesWan
48f5a975db 革命尚未成功?也许是库的问题,但是没时间检查了,先走了((( 2023-04-16 19:11:55 +08:00
EillesWan
acb347b491 新增一个依赖,减少一个文档,把文档移动到了MCS库里 2023-03-26 19:18:00 +08:00
EillesWan
6ca8820fa8 改个东西 2023-03-12 17:57:40 +08:00
EillesWan
fb4cd07dc6 新增MCSTRUCTURE结构文档 2023-03-12 17:43:52 +08:00
EillesWan
3db35b24ab Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-03-12 14:35:26 +08:00
EillesWan
a07f723d7c 这改了不啦,一代一代更新有个鬼用,什么都没变嘛;我带的是什么队啊,我带的是睿穆啊,先把这个理念搞懂嘛 2023-03-12 14:35:23 +08:00
EillesWan
7cc70d6948 修改部分文档 2023-03-11 18:23:40 +08:00
EillesWan
b1fb82712d Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-03-05 18:58:08 +08:00
EillesWan
bd329082c2 这不是最终版本,请不要提交更新 2023-03-05 18:58:05 +08:00
Eilles Wan
16be83ea29 update README.md.
Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2023-02-19 02:25:00 +00:00
EillesWan
5ffb654ec9 修复method3的时长bug 2023-02-12 17:34:03 +08:00
bgArray
7f5efea038 update 2023/2/12 bug fixed 2023-02-12 16:25:52 +08:00
EillesWan
5efabd5463 更新版本号 2023-02-12 16:11:21 +08:00
EillesWan
24fd0121a3 更新文档与依赖描述 2023-02-12 16:08:54 +08:00
EillesWan
a65be910a5 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-02-12 15:55:24 +08:00
EillesWan
15cd0ad777 little update 2023-02-12 15:55:09 +08:00
bgArray
4904f612e1 update 2023/2/5 小改 2023-02-05 17:56:06 +08:00
bgArray
27c6556693 update 2023/2/5 小改 2023-02-05 17:52:20 +08:00
EillesWan
26fbd346d8 新增第三种算法,解决通道与音轨的乐器问题;修复to_DICT中的音符时间问题 2023-02-05 16:16:12 +08:00
EillesWan
c419adc274 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2023-02-01 22:40:36 +08:00
EillesWan
f8926d2f4f 删除一些没用的文件 2023-02-01 22:40:24 +08:00
bgArray
4268139313 Merge remote-tracking branch 'origin/master' 2023-02-01 22:35:21 +08:00
bgArray
8b8334202c 2023/2/1 update pypi update 2023-02-01 22:35:09 +08:00
EillesWan
1cfbfe1ba1 新增安装教程 2023-02-01 22:31:21 +08:00
EillesWan
3669b5f804 Merge branch 'pkgver' of https://gitee.com/TriM-Organization/Musicreater 2023-02-01 22:10:35 +08:00
EillesWan
7146d17051 删除不必要的文件 2023-02-01 21:51:31 +08:00
EillesWan
8a21b6c3e7 同步仓库描述,准备合并至主版本 2023-02-01 21:48:12 +08:00
EillesWan
5cce59135a 修bug,准备合并 2023-02-01 19:19:40 +08:00
EillesWan
53fda9c986 修复部分bug,准备合并 2023-02-01 18:48:30 +08:00
EillesWan
75f94dab4c 准备与pkgver合并 2023-02-01 18:24:44 +08:00
bgArray
6aa557dcd2 2023/2/1 update fug fixed 2.1 2023-02-01 11:59:14 +08:00
bgArray
215bcafb64 2023/2/1 update fug fixed 2.0 2023-02-01 10:55:07 +08:00
bgArray
f568803b0d 2023/2/1 update fug fixed 2023-02-01 10:09:16 +08:00
EillesWan
a8c0c9e1d5 bug fixed 2023-01-31 21:06:22 +08:00
EillesWan
4d7a1b614a 修复部分bug again 2023-01-31 20:49:53 +08:00
EillesWan
975dbd71e3 新增一点教程 2023-01-31 20:47:09 +08:00
EillesWan
8722d4fd83 修复部分bug 2023-01-31 20:39:50 +08:00
EillesWan
8b9d9a78a3 bug fixed 2023-01-29 13:02:43 +08:00
bgArray
032bbb81c4 update 2023/1/28 formatting and blacking codes 2023-01-28 11:56:09 +08:00
bgArray
49c4cfcbe2 update 2023/1/27 formatting and fixing bugs 2023-01-27 23:25:28 +08:00
EillesWan
352807cba0 小bug能奈我何? 2023-01-27 22:16:15 +08:00
EillesWan
8e938b4f84 Merge branch 'pkgver' of https://gitee.com/TriM-Organization/Musicreater into pkgver 2023-01-27 02:19:56 +08:00
EillesWan
bf0ef8ebb2 新增 延迟播放器算法2、修复进度条无法显示播放百分比、播放时最大积分错误的bug 2023-01-27 02:19:53 +08:00
bgArray
c4664f0e0c add .gitattributes.
Signed-off-by: bgArray <474037765@qq.com>
2023-01-26 02:05:22 +00:00
EillesWan
65a21dcfa7 Bug Fixed 2023-01-24 17:28:05 +08:00
EillesWan
032e2f0f0a 更新部分文档,以及英文语言支持 2023-01-24 16:24:02 +08:00
EillesWan
87e80406a3 移除部分内容 2023-01-23 01:35:56 +08:00
EillesWan
41a6a84342 新增言论,修改其余部分的协议声明 2023-01-23 01:30:44 +08:00
EillesWan
4b9550db21 bug不过年 2023-01-22 00:04:09 +08:00
EillesWan
3d66c06e6d 修复一个小问题 2023-01-21 19:39:14 +08:00
EillesWan
9872a69a66 同时修复bug 2023-01-21 04:12:31 +08:00
EillesWan
0ce72fc4e3 避免GPL传染,我fo了 2023-01-21 04:11:53 +08:00
EillesWan
e0557da3cf 今年就这样罢,我摆了,紧急更新,修复一点点小bug 2023-01-20 22:26:04 +08:00
EillesWan
7d6faebc5b 增加调试功能,降低容错率(不是,我真的没有反向更新(((
但是修改了算法1,算法1的响度错误解决了。但是我仍然推荐算法2
2023-01-20 21:34:15 +08:00
EillesWan
502f4eb54d 紧急修复bug 2023-01-20 01:33:57 +08:00
EillesWan
290db45c23 更新文档 2023-01-20 01:03:59 +08:00
EillesWan
782395b6c9 除旧迎新,0.2.0大更新! 2023-01-20 00:33:09 +08:00
EillesWan
392e74d8d9 0.2.0前的预备更新 2023-01-20 00:31:45 +08:00
EillesWan
ebfaeafcda 更新新手指南文档 2023-01-07 01:19:13 +08:00
EillesWan
6955bb8eaf 完善文档 2023-01-06 12:32:18 +08:00
EillesWan
582e66cd58 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2023-01-05 17:30:39 +08:00
EillesWan
d64540bfd0 新增文档,修复小bug,更新版本 2023-01-05 17:30:36 +08:00
bgArray
63499732eb 2023/1/2 update-新手答疑指南.md 2023-01-02 16:40:17 +08:00
EillesWan
be40f8f920 改错版本号了qwq 2023-01-02 14:32:25 +08:00
EillesWan
190ef70fc4 忘了改版本号 2023-01-02 14:31:23 +08:00
EillesWan
a74fd4b4de 更加优秀的打击乐器判断! 2023-01-02 14:28:25 +08:00
EillesWan
13f7c0cda0 修改协议声明并新增名言警句 2023-01-02 00:35:08 +08:00
EillesWan
2ebdf6be24 修改版权声明以及部分教程文档 2023-01-01 03:23:48 +08:00
EillesWan
9ca0788eb2 准备修改协议 2022-12-31 13:21:30 +08:00
EillesWan
fba83ef968 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-12-31 13:20:32 +08:00
EillesWan
68e019412d 没写完,但是新算法 2022-12-31 13:20:30 +08:00
bgArray
bde2b4e378 update msctPkgver/main.py.
Signed-off-by: bgArray <474037765@qq.com>
2022-12-29 11:52:10 +00:00
bgArray
b04c01772f 更新指令格式 2022-12-29 11:09:30 +08:00
Eilles Wan
3cd85897fc update README.md.
Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-12-10 11:09:21 +00:00
Eilles Wan
00c2dcdeab update README.md.
Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-12-10 11:08:49 +00:00
EillesWan
88d36f94f0 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-11-27 18:13:05 +08:00
EillesWan
8eda5c4736 别急,没写完 2022-11-27 18:13:01 +08:00
Eilles Wan
37ccbe3dae 没翻译完,差不多就行
没翻译完

Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-11-25 04:40:51 +00:00
EillesWan
be43e4a92a 修复mcpack制作过程中的问题 2022-11-20 15:28:09 +08:00
EillesWan
5929ae417d 改太快了,出问题了,修复了 2022-11-20 12:26:28 +08:00
EillesWan
517c7db112 好玩~ 2022-11-20 12:16:59 +08:00
Eilles Wan
91c31d4e90 update resources/myWords.txt.
Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-11-20 04:09:02 +00:00
EillesWan
3ae456c4d1 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-11-20 12:02:45 +08:00
EillesWan
b0af5f4950 紧急修复文件路径问题和进度条问题(没修进度条,但是胜似修了) 2022-11-20 12:02:40 +08:00
Eilles Wan
1ccaa8e9aa update docs/功能使用说明.md.
Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-11-20 02:59:00 +00:00
EillesWan
8d1e6b2ecf 习语进人 2022-11-06 18:24:12 +08:00
EillesWan
75fabf9c37 行了,重要的不急 2022-10-30 01:58:29 +08:00
EillesWan
95e34f5c7b 不好意思,我急了 2022-10-30 01:40:53 +08:00
EillesWan
5bb0227a7a 没写完,不急 2022-10-30 01:39:20 +08:00
EillesWan
397825b483 更新 言·论 2022-10-29 22:26:52 +08:00
EillesWan
9c9ebe0a08 Bug++ 2022-10-23 02:12:11 +08:00
EillesWan
54d434404c 更新言·论 2022-10-16 23:32:13 +08:00
EillesWan
0b3a19faad 更新安卓端的使用方法说明 2022-10-16 23:16:46 +08:00
EillesWan
6cde168bf3 学校的更改 2022-10-16 21:19:14 +08:00
Eilles Wan
451d1d8e80 update msctPkgver/main.py.
插值OK

Signed-off-by: Eilles Wan <w-yi_doctoryi@outlook.com>
2022-10-07 12:23:02 +00:00
EillesWan
085ab3f4c0 没写完 2022-10-07 19:25:28 +08:00
EillesWan
a16109f29a 搞错了再来一发 2022-10-07 16:52:17 +08:00
EillesWan
813186bef9 快好了,不急不急 2022-10-07 16:49:47 +08:00
EillesWan
3921190832 okk准备睡觉 2022-10-06 00:06:41 +08:00
EillesWan
c32b94592a 更新文档及其翻译……,另外对无法批量转换带进度条的bug做了更正……现在批量可以用进度条了 2022-10-05 23:59:06 +08:00
EillesWan
77b7344277 把教程改了个名 2022-10-05 22:29:07 +08:00
EillesWan
0a17f8b8f8 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-10-05 22:27:55 +08:00
EillesWan
f8d707ac11 由于Merge错误,我得提交未完成的修改 2022-10-05 22:21:13 +08:00
EillesWan
ad7e047abc Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-10-05 22:18:15 +08:00
EillesWan
5ea47c54cb 这是学校里做的更新 2022-10-05 22:18:03 +08:00
EillesWan
5956e27d83 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-10-05 01:12:42 +08:00
EillesWan
b73a041883 更新文案 2022-10-05 01:12:37 +08:00
bgArray
36f1831cd1 update README.md.
Signed-off-by: bgArray <474037765@qq.com>
2022-09-25 14:58:11 +00:00
bgArray
b20f350da4 update README.md.
Signed-off-by: bgArray <474037765@qq.com>
2022-09-10 12:58:14 +00:00
Eilles
5aaae83020 呼呼,教程写完啦 2022-09-10 00:02:55 +08:00
Eilles
85e6340570 教程写完了,欧耶 2022-09-10 00:00:58 +08:00
Eilles
662c6506d8 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-09-09 22:58:59 +08:00
Eilles
ad2fcd6f14 更新demo的输入操作,一并增加教程 2022-09-09 22:58:05 +08:00
bgArray
5dde31d081 帮金羿提交,顺便改点小语法 2022-09-09 14:14:51 +08:00
bgArray
2e11a9949b 格式化 2022-09-08 22:36:01 +08:00
EillesWan
0a9c70f97c 更新依赖 2022-08-09 18:45:17 +08:00
EillesWan
814ab2ab0e 更新自动启动工具 2022-08-09 16:07:59 +08:00
EillesWan
3b53846ade ok 2022-08-09 15:13:25 +08:00
EillesWan
96af5183ac 库版 0.0.1 正式推出 2022-08-09 15:10:52 +08:00
EillesWan
4aebf9db16 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-08-09 12:54:25 +08:00
EillesWan
fff689446a 我真的不鸽 2022-08-09 12:54:18 +08:00
bgArray
59fd2645e4 update README.md. 2022-08-08 16:07:19 +00:00
bgArray
33ce7ed8c8 update README.md. 2022-08-08 15:57:07 +00:00
bgArray
14f7d6fd7e update README.md. 2022-08-08 15:52:01 +00:00
bgArray
fb2fd13b21 readme 更新 2022-08-08 23:49:22 +08:00
EillesWan
5025cba356 魔法计划启动! 2022-08-08 22:08:08 +08:00
EillesWan
abb53a7499 没改 2022-07-22 17:06:09 +08:00
EillesWan
73854be7be 格式化一下文档 2022-07-12 11:48:32 +08:00
EillesWan
6f6a77d0b4 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-07-12 11:46:49 +08:00
EillesWan
e0a3399fed 新增更新工具 2022-07-12 11:46:37 +08:00
CaryXiong
2afd6beb3f 更新 2022-06-30 12:14:22 +08:00
bgArray
9517c49ec5 修正库导入BUG 2022-06-28 07:43:15 +08:00
bgArray
887452184b update msctPkgver/load_InstrumentLabel.py. 2022-06-26 12:06:52 +00:00
Eilles Wan
d36134e525 诸葛八卦没改完
我来给他改一下,改完来,这家伙没料到我后面留了一手吧,qwq
2022-06-25 16:17:42 +00:00
bgArray
453ca745af 修改算法,修正bug 2022-06-25 23:20:56 +08:00
EillesWan
7d814bcda2 !!update 2022-06-25 22:21:12 +08:00
EillesWan
50dff06ac2 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-06-25 22:06:24 +08:00
EillesWan
d88e50819d 更了?没更 2022-06-25 22:06:19 +08:00
EillesWan
325bb37210 更了?没更…… 2022-06-25 22:04:01 +08:00
CaryXiong
55b933ac85 更新算法,使之适配多乐器 2022-06-24 13:46:46 +08:00
EillesWan
56fb029e75 新增批量转换新样例 2022-06-19 02:04:17 +08:00
EillesWan
c5a7dfb608 小改动 2022-06-19 01:39:50 +08:00
EillesWan
0a640267ff 修复进度条显示错误 2022-06-19 01:36:52 +08:00
EillesWan
a6d7022f87 修复错误 2022-06-19 01:26:53 +08:00
EillesWan
dcc62ca66d 完成延时播放器 2022-06-19 01:07:07 +08:00
EillesWan
4b53938adf 装逼 2022-06-12 18:38:31 +08:00
EillesWan
8502a02880 小改动 2022-06-12 18:22:07 +08:00
bgArray
80fab8ced0 update resources/msctDevAuthors.txt. 2022-06-12 00:19:36 +00:00
EillesWan
1980aeb8de 浅浅更新一下 2022-06-11 13:53:59 +08:00
CaryXiong
1fde8ca253 小改动 2022-06-11 12:19:15 +08:00
CaryXiong
0ce24bff92 小更新 2022-06-09 16:21:08 +08:00
EillesWan
992572cbf1 更新了一下文件结构 2022-06-08 01:50:14 +08:00
EillesWan
ce1099a246 我再更新一些小东西 2022-06-07 23:49:04 +08:00
EillesWan
2340741bb9 更新便于使用的预览程序 2022-06-07 23:43:14 +08:00
EillesWan
1f94f558c4 Merge 2022-06-07 23:12:42 +08:00
EillesWan
0c50ce1134 Merge 2022-06-07 23:12:06 +08:00
EillesWan
2e0dd06db6 更新延期!详见群内 2022-06-07 23:07:55 +08:00
Eilles Wan
9fd32d499f Update sth. 2022-05-26 18:40:33 +08:00
EillesWan
5c501a3466 更新个屁,Gitee脸都不要了 2022-05-21 00:47:54 +08:00
EillesWan
e872c19676 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-05-21 00:45:17 +08:00
EillesWan
51d248cdc2 更新个屁,Gitee脸都不要了 2022-05-21 00:45:10 +08:00
bgArray
a1dfe65042 add readme2.md. 2022-05-16 13:29:04 +00:00
bgArray
70fc686057 删除文件 readme2.md 2022-05-16 13:27:08 +00:00
bgArray
ba691d177a 删除文件 readme3.md 2022-05-16 13:27:02 +00:00
bgArray
b81860dadd update readme3.md. 2022-05-16 13:26:18 +00:00
bgArray
343a62be47 add readme3.md. 2022-05-16 13:24:32 +00:00
bgArray
ab26c82bf9 add readme2.md. 2022-05-16 13:23:47 +00:00
bgArray
a2ae755e87 删除文件 readme2.md 2022-05-16 13:23:21 +00:00
bgArray
e94af73c4f add readme2.md. 2022-05-16 13:22:00 +00:00
Eilles Wan
bc247e1507 Nothing, at all 2022-05-16 13:10:54 +00:00
Eilles Wan
874cd1aea9 Nothing 2022-05-16 13:09:34 +00:00
bgArray
5a6d874204 删除文件 readme2.md 2022-05-16 13:06:29 +00:00
bgArray
08ffa1a6e2 add readme2.md. 2022-05-16 13:05:51 +00:00
bgArray
16d0ecf009 删除文件 .idea 2022-05-16 13:00:01 +00:00
bgArray
f57f4257fb readme-- 2022-05-16 20:59:36 +08:00
EillesWan
3f0f714a7c Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-05-16 16:02:48 +08:00
EillesWan
65c23ca427 没问题 2022-05-16 16:02:43 +08:00
EillesWan
bc99f8f4be 更新requirement.txt 2022-05-11 23:41:08 +08:00
bgArray
3b6cb3865f 教程 2022-05-11 23:38:26 +08:00
EillesWan
64292a21b3 更新一点点 2022-05-11 21:34:16 +08:00
EillesWan
3ba8fdad8c Merge 2022-05-11 15:23:44 +08:00
EillesWan
7357a09e5f 无主要的修改,即将更换窗口库 2022-05-11 15:19:40 +08:00
EillesWan
cae0b7f23d 有bug 2022-05-08 18:33:28 +08:00
EillesWan
e1d4cd9933 更新自动重置积分、进度条的功能 2022-05-08 01:30:30 +08:00
bgArray
3bc19ac396 update README.md. 2022-05-06 11:59:04 +00:00
EillesWan
3499c05eb4 修复x轴不增加的bug 2022-04-29 23:17:14 +08:00
EillesWan
259fb04980 完成了更改,现在支持bdx导出 2022-04-29 18:45:06 +08:00
EillesWan
8ce7a9fa83 update format 2022-04-29 11:34:41 +08:00
EillesWan
affb5b5404 Merge branch 'pkgver' of https://gitee.com/EillesWan/Musicreater into pkgver 2022-04-29 11:33:52 +08:00
EillesWan
1805ab53c0 新增bdx转换功能 2022-04-29 11:29:49 +08:00
EillesWan
f3c5044800 撤销了disp类,但是bug依旧没有变化。 2022-04-24 17:56:57 +08:00
EillesWan
ca2e8c9155 更新。 2022-04-21 23:52:16 +08:00
bgArray
eda3a957cf 修复已知问题 2022-04-12 18:11:57 +08:00
bgArray
4788d8949b 格式化 2022-04-12 14:15:33 +08:00
EillesWan
1715735800 Merge 2022-04-08 01:29:39 +08:00
EillesWan
d22b5b0c42 我不知道这样有没有用,但是这确实是更新了bdx操作,我不知道bug在哪里 2022-04-08 01:26:35 +08:00
Eilles Wan
549dd3dbf9 删除文件 msctplugin 2022-04-07 16:19:48 +00:00
Eilles Wan
a65bfeba20 删除文件 Musicreater.New.py 2022-04-07 16:19:33 +00:00
EillesWan
7edf979aee 修复bdx生成不了的问题 2022-04-07 18:07:32 +08:00
EillesWan
8f6cc04780 重设样例代码 2022-04-07 08:27:43 +08:00
EillesWan
6cb5c9ba89 提交包模式的更新 2022-04-05 23:43:03 +08:00
EillesWan
ae83f9c21e 更新了内部数据格式文档,修复部分bug 2022-04-05 00:55:43 +08:00
EillesWan
dd34ac9998 紧急更新,修复了无法将整首歌转换bdx的bug,其余bug正在发现。 2022-04-03 21:38:17 +08:00
EillesWan
2da06136c5 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-04-03 00:51:39 +08:00
EillesWan
e9f4230a2d 金羿生日快乐~ 2022-04-03 00:51:34 +08:00
bgArray
1b7ab73c02 update README_EN.md. 2022-04-01 07:54:34 +00:00
EillesWan
2624c081bb 生活不易,改README出气 2022-04-01 15:09:03 +08:00
EillesWan
87cc189da8 修正单词拼写错误 2022-04-01 15:07:22 +08:00
Eilles Wan
668bf480b2 重命名 README_en.md 为 README_EN.md 2022-04-01 06:42:30 +00:00
EillesWan
4cc3f2678f 没事?没事就改README! 2022-04-01 14:38:50 +08:00
EillesWan
701e9d5129 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-04-01 14:23:08 +08:00
EillesWan
8dd2694e82 左改改右改改,就是不改代码/qwq 2022-04-01 14:23:03 +08:00
bgArray
ac962f0ab7 update README.md. 2022-04-01 05:50:48 +00:00
EillesWan
b800384547 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-04-01 12:48:41 +08:00
EillesWan
5da1041664 喵喵喵? 2022-04-01 12:48:35 +08:00
Eilles Wan
966ce515c3 update README.md. 2022-04-01 04:22:57 +00:00
EillesWan
349c255f5f LOGO 2022-04-01 11:53:43 +08:00
bgArray
cbb77086d0 update README.md. 2022-04-01 03:17:14 +00:00
bgArray
280e50f4cb update README.md. 2022-04-01 02:55:58 +00:00
bgArray
a2a37be8ef update README.md. 2022-04-01 02:33:10 +00:00
Eilles Wan
7acd6b7e38 update resources/myWords.txt. 移除上一次更改 2022-03-31 01:23:11 +00:00
bgArray
4c95f76cf9 update 道法重大更新 2022-03-30 03:01:08 +00:00
Eilles Wan
8a1a159eb8 update README.md. 2022-03-29 08:51:53 +00:00
Eilles Wan
cb43caef26 update README.md. 2022-03-29 08:51:29 +00:00
Eilles Wan
200167ef84 update README.md. 2022-03-29 08:51:23 +00:00
EillesWan
7e0a127406 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-03-29 16:46:40 +08:00
EillesWan
5e70dd73a1 重大更新,我新增了很多名言名句!!! 2022-03-29 16:46:31 +08:00
bgArray
7229b12e99 删除文件 languages/log 2022-03-28 15:13:37 +00:00
bgArray
074124bc3d 删除文件 .idea 2022-03-28 15:13:09 +00:00
bgArray
91446bfd81 翻译保存器 2022-03-28 23:12:24 +08:00
EillesWan
5011efcdee Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-03-28 20:42:12 +08:00
EillesWan
3b4af19379 暂存更改以便pull 2022-03-28 20:40:17 +08:00
EillesWan
d3d89d2567 增强对于Linux的支持 2022-03-28 20:29:36 +08:00
EillesWan
441d1e9982 我把旧的MMFM的日志一起加入进来,作为历史的参考。 2022-03-28 14:04:30 +08:00
EillesWan
77e738cb7e 修改读我档 2022-03-28 12:33:35 +08:00
EillesWan
46b6884e64 Merge branch 'master' of https://gitee.com/EillesWan/Musicreater 2022-03-26 21:01:29 +08:00
EillesWan
d0a63d0f8e 为了pull,暂存更改 2022-03-26 21:01:23 +08:00
171 changed files with 6122 additions and 8113 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
*.yaml linguist-language=Python
*.xml linguist-language=Python
*.md linguist-language=Python

164
.gitignore vendored Normal file
View File

@@ -0,0 +1,164 @@
# sth. can't open
/msctPkgver/secrets/*.py
/msctPkgver/secrets/*.c
# mystuff
/.vscode
*.mid
*.midi
*.mcpack
*.bdx
*.json
*.mcstructure
/logs
/languages
/llc_cli.py
/utils
test.py
RES.txt
# Byte-compiled / optimized
__pycache__/
*.pyc
*$py.class
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# Pycharm
/.idea
# log
/.log
# package
.7z

View File

@@ -1,221 +0,0 @@
# -*- coding: utf-8 -*-
# W-YI 金羿
# QQ 2647547478
# 音·创 开发交流群 861684859
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
# 版权所有 Team-Ryoun 金羿("Eilles Wan")
# 若需转载或借鉴 请附作者
"""
音·创自动安装器 (Musicreater Auto Installer)
对音·创的自动安装提供支持的独立软件
Musicreater Auto Installer (音·创自动安装器)
A software that used for installing Musicreater automatically
Copyright 2022 Team-Ryoun
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# 代码写的并非十分的漂亮还请大佬多多包涵本软件源代码依照Apache软件协议公开
# 下面为正文
from sys import platform
from platform import architecture
import urllib.request
import zipfile
from os import system as srun
from os import walk, rename, remove, path, chdir, listdir
from shutil import rmtree, move
if platform == "win32":
nowpath = __file__[: len(__file__) - __file__[len(__file__) :: -1].index('\\')]
if srun('python -V'):
print('\033[7m{}\033[0m'.format("正在下载python\nDownloading Python"))
try:
urllib.request.urlretrieve(
"https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe"
if architecture()[0] == "32bit"
else "https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe",
"./pythonInstaller.exe",
)
# urllib.request.urlretrieve("https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe","./pythonInstaller.exe")
except Exception as E:
input(str(E) + "\n自动下载失败,按下回车取消")
exit()
print('正在安装python\nInstalling Python')
# open('install.bat','w').write(f'.\\pythonInstaller.exe /passive InstallAllUsers=0 TargetDir="{nowpath}python38" DefaultJustForMeTargetDir="{nowpath}python38" AssociateFiles=0 CompileAll=1 PrependPath=0 Shortcuts=0 Include_doc=0 Include_launcher=0 InstallLauncherAllUsers=0 Include_test=0 Include_tools=0')
srun(
f'.\\pythonInstaller.exe /passive InstallAllUsers=1 AssociateFiles=1 CompileAll=1 PrependPath=1 Shortcuts=1 Include_doc=0 Include_exe=1 Include_pip=1 Include_lib=1 Include_tcltk=1 Include_launcher=1 InstallLauncherAllUsers=1 Include_test=0 Include_tools=0'
)
remove('./pythonInstaller.exe')
# print('\033[7m{}\033[0m'.format("正在下载pip安装工具\nDownloading get-pip tool"))
# try:
# urllib.request.urlretrieve(
# "https://bootstrap.pypa.io/get-pip.py", "./python38/get-pip.py"
# )
# except Exception as E:
# input(str(E) + "\n自动下载失败按下回车取消")
# exit()
# print('\033[7m{}\033[0m'.format("正在下载pip\nDownloading pip"))
# chdir('./python38')
# srun(r'".\python.exe get-pip.py')
# print('\033[7m{}\033[0m'.format('正在安装pip\nInstalling pip'))
# for dire in listdir('./Lib/site-packages/'):
# move('./Lib/site-packages/'+dire,'./'+dire)
# print('\033[7m{}\033[0m'.format("完成!"))
# chdir('../')
try:
choseurl = int(
input(
'\033[7m{}\033[0m'.format(
"""请选择 音·创 下载源,默认为0
Please choose a download source of Musicreater(default 0)
[0] 私有服务器<暂无> | Private Server<Haven't been built>
[1] Gitee
[2] Github\n:"""
)
)
)
except Exception as E:
print('\033[7m{}\033[0m'.format(str(E) + "\n将使用默认源\nUsing default source"))
choseurl = 0
myurl = ""
Giteeurl = "https://gitee.com/EillesWan/Musicreater/repository/blazearchive/master.zip?Expires=1647771436&Signature=%2BkqLHwmvzScCd4cPQDP0LHLpqeZUxOrOv17QpRy%2FTzs%3D"
Githuburl = (
"https://codeload.github.com/EillesWan/Musicreater/zip/refs/heads/master"
)
url = (
myurl
if choseurl == 0
else Giteeurl
if choseurl == 1
else Githuburl
if choseurl == 2
else myurl
)
print('\033[7m{}\033[0m'.format("正在下载音·创\nDownloading Musicreater"))
try:
urllib.request.urlretrieve(url, "./master.zip")
except Exception as E:
input('\033[0{}\033[0m'.format(str(E) + "\n自动下载失败,按下回车取消"))
exit()
print('\033[7m{}\033[0m'.format("安装音·创\nInstalling Musicreater"))
zipfile.ZipFile("./master.zip", "r").extractall()
remove("./master.zip")
try:
rmtree("./Musicreater")
except:
pass
rename("./Musicreater-master/", "./Musicreater/")
elif platform == 'linux':
srun("sudo apt-get install python3")
srun("sudo apt-get install python3-pip")
srun("sudo apt-get install git")
try:
choseurl = int(
input(
'\033[0{}\033[0m'.format(
"""请选择 音·创 下载源,默认为1
Please choose a download source of Musicreater(default 1)
[1] Gitee
[2] Github\n:"""
)
)
)
except Exception as E:
print(str(E) + "\n将使用默认源\nUsing default source")
choseurl = 1
url = (
"https://gitee.com/EillesWan/Musicreater.git"
if choseurl == 1
else "https://github.com/EillesWan/Musicreater.git"
if choseurl == 2
else "https://gitee.com/EillesWan/Musicreater.git"
)
srun(f"sudo git clone {url}")
print('\033[7m{}\033[0m'.format("编译音·创\nCompiling Musicreater"))
if platform == "linux":
srun("python3 -O -m compileall -b ./Musicreater/")
elif platform == "win32":
srun("python -O -m compileall -b ./Musicreater/")
for parent, dirnames, filenames in walk("./Musicreater"):
for filename in filenames:
if filename[-3:] == ".py":
fn = path.join(parent, filename)
remove(fn)
print(f"删除文件 {fn}")
for dirname in dirnames:
if dirname == "__pycache__":
pn = path.join(parent, dirname)
rmtree(pn)
print(f"删除目录 {pn}")
print(
'\033[7m{}\033[0m'.format(
"""您可以开始使用音·创了
我们将在后台为您安装各项支持库
您可以运行Musicreater文件夹中的Musicreater.pyc文件来运行音·创
You can use Musicreater now,
We will setup the libraries ineed for you in background,
You can now open Musicreater.PYC in the directory of ./Musicreater to run Musicreater
"""
)
)
if platform == "linux":
srun("python3 ./Musicreater/补全库.pyc")
elif platform == "win32":
srun("python ./Musicreater/补全库.pyc")

View File

@@ -1,192 +1,219 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2022 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**注意以下条款或版权声明应当且必须是高于此项目中任何其他声明的**
1. ·创的全部开发者享有其完整版权其开发者可以在任一时刻终止以后音·创源代码开放若经由其开发者授予特殊权利则授权对象可以将源代码进行特定的被特殊授权的操作
2. ·创或其代码允许在 Apache2.0 协议的条款与说明下进行非商业使用
3. 除部分代码特殊声明外·创允许对其或其代码进行商业化使用但是需要经过音·创主要开发者诸葛亮与八卦阵金羿的一致授权同时授权对象在商业化授权的使用过程中必须依照 Apache2.0 协议的条款与说明
4. 若存在对于音·创包含的部分代码的特殊开源声明则此部分代码依照其特定的开源方式授权但若此部分代码经由此部分代码的主要开发者一致特殊授权后商用则授权对象在商用时依照此部分的开发者所准许的方式或条款进行商用
5. Apache2.0 协议的英文原文副本可见下文
> The English Translation of the TERMS AND CONDITIONS above is listed below
>
> This translated version is for reference only and has no legal effect.
>
> The version with legal effect is the Chinese version above.
**Note, The TERMS AND CONDITIONS below should and must be above all others in this project**
1. *Musicreater* is fully copyrighted by all its developers, the developers have the right to make *Musicreater* close sourced at any time. Operations are permitted under specific terms instructed by its developer(s).
2. Non-commercial use of *Musicreater* and(or) its source code is permitted under Apache License 2.0.
3. Commercial use of *Musicreater* is permitted under Apache License 2.0 with the unanimous permission of the steering developers of *Musicreater* (*bgArray*诸葛亮与八卦阵 and *Eilles*金羿).
4. *Musicreater* is open sourced under priority given:
1. License granted by the core developer(s) of a section after negotiation.
2. Explicitly stated license.
3. Apache 2.0 License.
5. A copy of the original Apache Lisence 2.0 can be found below.
```text
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2022 TriM-Organization 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & all the developers of Musicreater
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

View File

@@ -1,69 +0,0 @@
# -*- coding: utf-8 -*-
# W-YI 金羿
# QQ 2647547478
# 音·创 开发交流群 861684859
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
# 版权所有 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
# 若需转载或借鉴 请附作者
"""
音·创 (Musicreater)
一款免费开源的 《我的世界:基岩版》 音乐制作软件
Musicreater (音·创)
A free opensource software which is used for creating all kinds of musics in Minecraft
Copyright 2022 Team-Ryoun
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# 代码写的并非十分的漂亮还请大佬多多包涵本软件源代码依照Apache软件协议公开
# 下面为正文
from msctspt.bugReporter import version
__ver__ = f'{version.version[1]} {version.version[0]}'
__author__ = '金羿Eilles'
from msctLib.display import *
from msctLib.function import *
from msctLib.data import uniteIO
def __main__():
disp()
if __name__ == '__main__':
__main__()

File diff suppressed because it is too large Load Diff

32
Musicreater/__init__.py Normal file
View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
"""一个简单的我的世界音频转换库
音·创 (Musicreater)
是一款免费开源的针对《我的世界》的midi音乐转换库
Musicreater(音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__version__ = "1.4.0"
__vername__ = "红石指令音乐的生成"
__author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray"), ("鸣凤鸽子", "MingFengPigeon"))
__all__ = [
# 主要类
"MidiConvert",
# 附加类
# "SingleNote",
"SingleCommand",
# "TimeStamp", 未来功能
]
from .main import *

295
Musicreater/constants.py Normal file
View File

@@ -0,0 +1,295 @@
# -*- coding: utf-8 -*-
from typing import Dict, List, Tuple
"""
存放常量与数值性内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
x = "x"
"""
x
"""
y = "y"
"""
y
"""
z = "z"
"""
z
"""
DEFAULT_PROGRESSBAR_STYLE = (
r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
("§e=§r", "§7=§r"),
)
"""
默认的进度条样式组
"""
# 以下是由 Touch “偷吃” 带来的高准确率音效对照表
# 包括乐音乐器对照和打击乐器对照
PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
0: ("note.harp", 6),
1: ("note.harp", 6),
2: ("note.pling", 6),
3: ("note.harp", 6),
4: ("note.pling", 6),
5: ("note.pling", 6),
6: ("note.guitar", 7),
7: ("note.harp", 6),
8: ("note.bell", 4), # 打击乐器无音域
9: ("note.bell", 4),
10: ("note.iron_xylophone", 6),
11: ("note.iron_xylophone", 6),
12: ("note.iron_xylophone", 6),
13: ("note.xylophone", 4),
14: ("note.chime", 4),
15: ("note.harp", 6),
16: ("note.bass", 8),
17: ("note.harp", 6),
18: ("note.flute", 5),
19: ("note.harp", 6),
20: ("note.harp", 6),
21: ("note.flute", 5),
22: ("note.flute", 5),
23: ("note.guitar", 7),
24: ("note.guitar", 7),
25: ("note.guitar", 7),
26: ("note.guitar", 7),
27: ("note.guitar", 7),
28: ("note.guitar", 7),
29: ("note.guitar", 7),
30: ("note.guitar", 7),
31: ("note.bass", 8),
32: ("note.bass", 8),
33: ("note.bass", 8),
34: ("note.bass", 8),
35: ("note.bass", 8),
36: ("note.bass", 8),
37: ("note.bass", 8),
38: ("note.bass", 8),
39: ("note.bass", 8),
40: ("note.flute", 5),
41: ("note.flute", 5),
42: ("note.flute", 5),
43: ("note.flute", 5),
44: ("note.iron_xylophone", 6),
45: ("note.guitar", 7),
46: ("note.harp", 6),
47: ("note.bd", 7),
48: ("note.guitar", 7),
49: ("note.guitar", 7),
50: ("note.bit", 6),
51: ("note.bit", 6),
52: ("note.flute", 5),
53: ("note.flute", 5),
54: ("note.flute", 5),
55: ("note.flute", 5),
56: ("note.flute", 5),
57: ("note.flute", 5),
58: ("note.flute", 5),
59: ("note.flute", 5),
60: ("note.flute", 5),
61: ("note.flute", 5),
62: ("note.flute", 5),
63: ("note.flute", 5),
64: ("note.bit", 6),
65: ("note.bit", 6),
66: ("note.bit", 6),
67: ("note.bit", 6),
68: ("note.flute", 5),
69: ("note.bit", 6),
70: ("note.banjo", 6),
71: ("note.flute", 5),
72: ("note.flute", 5),
73: ("note.flute", 5),
74: ("note.flute", 5),
75: ("note.flute", 5),
76: ("note.harp", 6),
77: ("note.harp", 6),
78: ("note.flute", 5),
79: ("note.harp", 6),
80: ("note.bit", 6),
81: ("note.bit", 6),
82: ("note.bit", 6),
83: ("note.bit", 6),
84: ("note.bit", 6),
85: ("note.bit", 6),
86: ("note.bit", 6),
87: ("note.bit", 6),
88: ("note.bit", 6),
89: ("note.bit", 6),
90: ("note.bit", 6),
91: ("note.bit", 6),
92: ("note.bit", 6),
93: ("note.bit", 6),
94: ("note.bit", 6),
95: ("note.bit", 6),
96: ("note.bit", 6),
97: ("note.bit", 6),
98: ("note.bit", 6),
99: ("note.bit", 6),
100: ("note.bit", 6),
101: ("note.bit", 6),
102: ("note.bit", 6),
103: ("note.bit", 6),
104: ("note.harp", 6),
105: ("note.banjo", 6),
106: ("note.harp", 6),
107: ("note.harp", 6),
108: ("note.bell", 4),
109: ("note.flute", 5),
110: ("note.flute", 5),
111: ("note.guitar", 7),
112: ("note.bell", 4),
113: ("note.bell", 4),
114: ("note.flute", 5),
115: ("note.cow_bell", 5),
116: ("note.bd", 7), # 打击乐器无音域
117: ("note.bass", 8),
118: ("note.bit", 6),
119: ("firework.blast", 7), # 打击乐器无音域
120: ("note.guitar", 7),
121: ("note.harp", 6),
122: ("note.harp", 6),
123: ("note.harp", 6),
124: ("note.harp", 6),
125: ("note.hat", 7), # 打击乐器无音域
126: ("firework.twinkle", 7), # 打击乐器无音域
127: ("note.snare", 7), # 打击乐器无音域
}
PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
34: ("note.bd", 7),
35: ("note.bd", 7),
36: ("note.hat", 7),
37: ("note.snare", 7),
38: ("note.snare", 7),
39: ("fire.ignite", 7),
40: ("note.hat", 7),
41: ("note.snare", 7),
42: ("note.hat", 7),
43: ("note.snare", 7),
44: ("note.snare", 7),
45: ("note.bell", 4),
46: ("note.snare", 7),
47: ("note.snare", 7),
48: ("note.bell", 4),
49: ("note.hat", 7),
50: ("note.bell", 4),
51: ("note.bell", 4),
52: ("note.bell", 4),
53: ("note.bell", 4),
54: ("note.bell", 4),
55: ("note.bell", 4),
56: ("note.snare", 7),
57: ("note.hat", 7),
58: ("note.chime", 4),
59: ("note.iron_xylophone", 6),
60: ("note.bd", 7),
61: ("note.bd", 7),
62: ("note.xylophone", 4),
63: ("note.xylophone", 4),
64: ("note.xylophone", 4),
65: ("note.hat", 7),
66: ("note.bell", 4),
67: ("note.bell", 4),
68: ("note.hat", 7),
69: ("note.hat", 7),
70: ("note.flute", 5),
71: ("note.flute", 5),
72: ("note.hat", 7),
73: ("note.hat", 7),
74: ("note.xylophone", 4),
75: ("note.hat", 7),
76: ("note.hat", 7),
77: ("note.xylophone", 4),
78: ("note.xylophone", 4),
79: ("note.bell", 4),
80: ("note.bell", 4),
}
PERCUSSION_INSTRUMENT_LIST: List[str] = [
"note.snare",
"note.bd",
"note.hat",
"note.basedrum",
"firework.blast",
"firework.twinkle",
"fire.ignite",
]
INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str]] = {
"note.bass": ("planks",),
"note.snare": ("sand",),
"note.hat": ("glass",),
"note.bd": ("stone",),
"note.basedrum": ("stone",),
"note.bell": ("gold_block",),
"note.flute": ("clay",),
"note.chime": ("packed_ice",),
"note.guitar": ("wool",),
"note.xylobone": ("bone_block",),
"note.iron_xylophone": ("iron_block",),
"note.cow_bell": ("soul_sand",),
"note.didgeridoo": ("pumpkin",),
"note.bit": ("emerald_block",),
"note.banjo": ("hay_block",),
"note.pling": ("glowstone",),
"note.bassattack": ("command_block",), # 无法找到此音效
"note.harp": ("dirt",),
# 呃……
"firework.blast": ("sandstone",),
"firework.twinkle": ("red_sandstone",),
"fire.ignite": ("concrete_powder",),
}
# 即将启用
height2note = {
0.5: 0,
0.53: 1,
0.56: 2,
0.6: 3,
0.63: 4,
0.67: 5,
0.7: 6,
0.75: 7,
0.8: 8,
0.84: 9,
0.9: 10,
0.94: 11,
1.0: 12,
1.05: 13,
1.12: 14,
1.2: 15,
1.25: 16,
1.33: 17,
1.4: 18,
1.5: 19,
1.6: 20,
1.7: 21,
1.8: 22,
1.9: 23,
2.0: 24,
}
"""音高对照表\n
MC音高:音符盒音调"""

106
Musicreater/exceptions.py Normal file
View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
"""
存放一堆报错类型
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
class MSCTBaseException(Exception):
"""音·创库版本的所有错误均继承于此"""
def __init__(self, *args):
"""音·创库版本的所有错误均继承于此"""
super().__init__(*args)
def miao(
self,
):
for i in self.args:
print(i + "喵!")
def crash_it(self):
raise self
class MidiFormatException(MSCTBaseException):
"""音·创库版本的所有MIDI格式错误均继承于此"""
def __init__(self, *args):
"""音·创库版本的所有MIDI格式错误均继承于此"""
super().__init__("MIDI格式错误", *args)
class MidiDestroyedError(MSCTBaseException):
"""Midi文件损坏"""
def __init__(self, *args):
"""Midi文件损坏"""
super().__init__("MIDI文件损坏无法读取MIDI文件", *args)
class MidiUnboundError(MSCTBaseException):
"""未定义Midi对象"""
def __init__(self, *args):
"""未绑定Midi对象"""
super().__init__("未定义MidiFile对象你甚至没有对象就想要生孩子", *args)
class CommandFormatError(RuntimeError):
"""指令格式与目标格式不匹配而引起的错误"""
def __init__(self, *args):
"""指令格式与目标格式不匹配而引起的错误"""
super().__init__("指令格式不匹配", *args)
class CrossNoteError(MidiFormatException):
"""同通道下同音符交叉出现所产生的错误"""
def __init__(self, *args):
"""同通道下同音符交叉出现所产生的错误"""
super().__init__("同通道下同音符交叉", *args)
class NotDefineTempoError(MidiFormatException):
"""没有Tempo设定导致时间无法计算的错误"""
def __init__(self, *args):
"""没有Tempo设定导致时间无法计算的错误"""
super().__init__("在曲目开始时没有声明Tempo未指定拍长", *args)
class ChannelOverFlowError(MidiFormatException):
"""一个midi中含有过多的通道"""
def __init__(self, max_channel=16, *args):
"""一个midi中含有过多的通道"""
super().__init__("含有过多的通道(数量应≤{}".format(max_channel), *args)
class NotDefineProgramError(MidiFormatException):
"""没有Program设定导致没有乐器可以选择的错误"""
def __init__(self, *args):
"""没有Program设定导致没有乐器可以选择的错误"""
super().__init__("未指定演奏乐器", *args)
class ZeroSpeedError(MidiFormatException):
"""以0作为播放速度的错误"""
def __init__(self, *args):
"""以0作为播放速度的错误"""
super().__init__("播放速度为0", *args)

623
Musicreater/experiment.py Normal file
View File

@@ -0,0 +1,623 @@
# -*- coding: utf-8 -*-
"""
新版本功能以及即将启用的函数
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import random
from typing import Dict, List, Tuple, Union
from .constants import INSTRUMENT_BLOCKS_TABLE
from .exceptions import *
from .main import MidiConvert
from .subclass import *
from .utils import *
class FutureMidiConvertRSNB(MidiConvert):
"""
加入红石音乐适配
"""
music_command_list: Dict[int, SingleNoteBox]
"""音乐指令列表"""
@staticmethod
def soundID_to_block(sound_id: str, random_select: bool = False) -> str:
"""
将我的世界乐器名改作音符盒所需的对应方块名称
Parameters
----------
sound_id: str
将我的世界乐器名
random_select: bool
是否随机选取对应方块
Returns
-------
str方块名称
"""
try:
if random_select:
return random.choice(INSTRUMENT_BLOCKS_TABLE[sound_id])
else:
return INSTRUMENT_BLOCKS_TABLE[sound_id][0]
except KeyError:
return "air"
def to_note_list_in_delay(
self,
) -> Tuple[Dict[int, SingleNoteBox], int]:
"""
使用金羿的转换思路将midi转换为我的世界音符盒音高、乐器及延迟列表并输出每个音符之后的延迟
Returns
-------
tuple( Dict[int, SingleNoteBox], int音乐时长游戏刻 )
"""
self.to_music_channels()
tracks = {}
note_range = {}
InstID = -1
# cmd_amount = 0
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
# block_id = self.soundID_to_block((
# self.perc_inst_to_soundID_withX(msg[1])
# if SpecialBits
# else self.inst_to_souldID_withX(InstID)
# )[0])
# delaytime_now = round(msg[-1] / 50)
note_ = 2 ** ((msg[1] - 60) / 12)
try:
tracks[msg[-1]].append(
(
InstID,
note_,
)
)
except KeyError:
tracks[msg[-1]] = [(InstID, note_)]
try:
note_range[InstID]["max"] = max(
note_range[InstID]["max"], note_
)
note_range[InstID]["min"] = min(
note_range[InstID]["min"], note_
)
except KeyError:
note_range[InstID] = {"max": note_, "min": note_}
del InstID
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
print(note_range)
exit()
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
annotation="{}播放{}%{}".format(
mctick2timestr(i), max_volume * 100, ""
),
)
)
self.music_command_list = results
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num
class FutureMidiConvertM4(MidiConvert):
"""
加入插值算法优化音感
: 经测试,生成效果已经达到,感觉良好
"""
# 临时用的插值计算函数
@staticmethod
def _linear_note(
_note: SingleNote,
_apply_time_division: int = 100,
) -> List[Tuple[int, int, int, int, float],]:
"""传入音符数据,返回以半秒为分割的插值列表
:param _note: SingleNote 音符
:return list[tuple(int开始时间毫秒, int乐器, int音符, int力度内置, float音量播放),]"""
totalCount = int(_note.duration / _apply_time_division)
if totalCount == 0:
return [
(_note.start_time, _note.inst, _note.pitch, _note.velocity, 1),
]
# print(totalCount)
result: List[Tuple[int, int, int, int, float],] = []
for _i in range(totalCount):
result.append(
(
_note.start_time + _i * _apply_time_division,
_note.instrument,
_note.pitch,
_note.velocity,
((totalCount - _i) / totalCount),
)
)
return result
# 简单的单音填充
def to_command_list_in_score(
self,
scoreboard_name: str = "mscplay",
max_volume: float = 1.0,
speed: float = 1.0,
) -> Tuple[List[List[SingleCommand]], int, int]:
"""
使用金羿的转换思路使用完全填充算法优化音感后将midi转换为我的世界命令列表
Parameters
----------
scoreboard_name: str
我的世界的计分板名称
max_volume: float
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
Returns
-------
tuple( list[list[SingleCommand指令,... ],... ], int指令数量, int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels()
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
InstID = -1
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# nowChannel = []
for track_no, track in self.channels[i].items():
noteMsgs = []
MsgIndex = []
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
noteMsgs.append(msg[1:])
MsgIndex.append(msg[1])
elif msg[0] == "NoteE":
if msg[1] in MsgIndex:
note_channels[i].append(
SingleNote(
InstID,
msg[1],
noteMsgs[MsgIndex.index(msg[1])][1],
noteMsgs[MsgIndex.index(msg[1])][2],
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
track_number=track_no,
)
)
noteMsgs.pop(MsgIndex.index(msg[1]))
MsgIndex.pop(MsgIndex.index(msg[1]))
del InstID
tracks = []
cmd_amount = 0
max_score = 0
# 此处 我们把通道视为音轨
for no, track in note_channels.items():
# 如果当前通道为空 则跳过
if not track:
continue
SpecialBits = True if no == 9 else False
track_now = []
for note in track:
for every_note in self._linear_note(
note, 50 if note.track_no == 0 else 500
):
soundID, _X = (
self.perc_inst_to_soundID_withX(note.pitch)
if SpecialBits
else self.inst_to_souldID_withX(note.inst)
)
score_now = round(every_note[0] / speed / 50)
max_score = max(max_score, score_now)
mc_pitch = 2 ** ((note.pitch - 60 - _X) / 12)
blockmeter = (
1
/ (1 if note.track_no == 0 else 0.9)
/ max_volume
/ every_note[4]
- 1
)
track_now.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores=({}={})]".format(scoreboard_name, score_now)
.replace("(", r"{")
.replace(")", r"}")
)
+ "playsound {} @s ^ ^ ^{} {} {}".format(
soundID,
blockmeter,
note.velocity / 128,
"" if SpecialBits else mc_pitch,
),
annotation="{}播放{}%({}BM)的{}".format(
mctick2timestr(score_now),
max_volume * 100,
blockmeter,
"{}:{}".format(soundID, note.pitch),
),
),
)
cmd_amount += 1
if track_now:
self.music_command_list.extend(track_now)
tracks.append(track_now)
self.music_tick_num = max_score
return (tracks, cmd_amount, max_score)
# 简单的单音填充的延迟应用
def to_command_list_in_delay(
self,
max_volume: float = 1.0,
speed: float = 1.0,
player_selector: str = "@a",
) -> Tuple[List[SingleCommand], int]:
"""
使用金羿的转换思路使用完全填充算法优化音感后将midi转换为我的世界命令列表并输出每个音符之后的延迟
Parameters
----------
max_volume: float
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
player_selector: str
玩家选择器,默认为`@a`
Returns
-------
tuple( list[SingleCommand,...], int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels()
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
InstID = -1
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# nowChannel = []
for track_no, track in self.channels[i].items():
noteMsgs = []
MsgIndex = []
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
noteMsgs.append(msg[1:])
MsgIndex.append(msg[1])
elif msg[0] == "NoteE":
if msg[1] in MsgIndex:
note_channels[i].append(
SingleNote(
InstID,
msg[1],
noteMsgs[MsgIndex.index(msg[1])][1],
noteMsgs[MsgIndex.index(msg[1])][2],
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
track_number=track_no,
)
)
noteMsgs.pop(MsgIndex.index(msg[1]))
MsgIndex.pop(MsgIndex.index(msg[1]))
del InstID
tracks = {}
InstID = -1
# open("RES.TXT", "w", encoding="utf-8").write(str(note_channels))
# 此处 我们把通道视为音轨
for no, track in note_channels.items():
# 如果当前通道为空 则跳过
if not track:
continue
SpecialBits = True if no == 9 else False
for note in track:
for every_note in self._linear_note(
note, 50 if note.track_no == 0 else 500
):
soundID, _X = (
self.perc_inst_to_soundID_withX(note.pitch)
if SpecialBits
else self.inst_to_souldID_withX(note.inst)
)
score_now = round(every_note[0] / speed / 50)
try:
tracks[score_now].append(
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
)
)
except KeyError:
tracks[score_now] = [
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
)
]
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
annotation="{}播放{}%{}".format(
mctick2timestr(i), max_volume * 100, ""
),
)
)
self.music_command_list = results
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num
class FutureMidiConvertM5(MidiConvert):
"""
加入同刻偏移算法优化音感
"""
# 神奇的偏移音
def to_command_list_in_delay(
self,
max_volume: float = 1.0,
speed: float = 1.0,
player_selector: str = "@a",
) -> Tuple[List[SingleCommand], int]:
"""
使用金羿的转换思路使用同刻偏移算法优化音感后将midi转换为我的世界命令列表并输出每个音符之后的延迟
Parameters
----------
max_volume: float
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
player_selector: str
玩家选择器,默认为`@a`
Returns
-------
tuple( list[SingleCommand,...], int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels()
tracks = {}
InstID = -1
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
# nowChannel = []
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1])
if SpecialBits
else self.inst_to_souldID_withX(InstID)
)
score_now = round(msg[-1] / float(speed) / 50)
# print(score_now)
try:
tracks[score_now].append(
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{128 / max_volume / msg[2] - 1} {msg[2] / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
)
except KeyError:
tracks[score_now] = [
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{128 / max_volume / msg[2] - 1} {msg[2] / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
]
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
(
0
if (
(all_ticks[i + 1] - all_ticks[i])
/ len(tracks[all_ticks[i]])
< 1
)
else 1
)
if j != 0
else (
(
all_ticks[i]
- all_ticks[i - 1]
- (
0
if (
(all_ticks[i] - all_ticks[i - 1])
/ len(tracks[all_ticks[i - 1]])
< 1
)
else (len(tracks[all_ticks[i - 1]]) - 1)
)
)
if i != 0
else all_ticks[i]
)
),
annotation="{}播放{}%{}".format(
mctick2timestr(
i + 0
if (
(all_ticks[i + 1] - all_ticks[i])
/ len(tracks[all_ticks[i]])
< 1
)
else j
),
max_volume * 100,
"",
),
)
)
self.music_command_list = results
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num
class FutureMidiConvertM6(MidiConvert):
"""
加入插值算法优化音感,但仅用于第一音轨
"""
# TODO 没写完的!!!!

225
Musicreater/magicmain.py Normal file
View File

@@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
"""
功能测试 若非已知 请勿更改
此文件仅供功能测试,并非实际调用的文件
请注意,此处的文件均为测试使用
不要更改 不要更改 不要更改
请注意这里的一切均需要其原作者更改
这里用于放置一些新奇的点子
用于测试
不要更改 不要更改 不要更改!
"""
# 音·创 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon")
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
"""
音·创 (Musicreater)
是一款免费开源的针对《我的世界》的midi音乐转换库
Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 ../License.md
Terms & Conditions: ../License.md
"""
# ============================
import mido
class NoteMessage:
def __init__(self, channel, pitch, velocity, startT, lastT, midi, now_bpm, change_bpm=None):
self.channel = channel
self.note = pitch
self.velocity = velocity
self.startTime = startT
self.lastTime = lastT
self.tempo = now_bpm # 这里要程序实现获取bpm可以参考我的程序
def mt2gt(mt, tpb_a, bpm_a):
return mt / tpb_a / bpm_a * 60
self.startTrueTime = mt2gt(self.startTime, midi.ticks_per_beat, self.tempo) # / 20
# delete_extra_zero(round_up())
if change_bpm is not None:
self.lastTrueTime = mt2gt(self.lastTime, midi.ticks_per_beat, change_bpm) # / 20
else:
self.lastTrueTime = mt2gt(self.lastTime, midi.ticks_per_beat, self.tempo) # / 20
# delete_extra_zero(round_up())
print((self.startTime * self.tempo) / (midi.ticks_per_beat * 50000))
def __str__(self):
return "noteMessage channel=" + str(self.channel) + " note=" + str(self.note) + " velocity=" + \
str(self.velocity) + " startTime=" + str(self.startTime) + " lastTime=" + str(self.lastTime) + \
" startTrueTime=" + str(self.startTrueTime) + " lastTrueTime=" + str(self.lastTrueTime)
def load(mid: mido.MidiFile):
type_ = [False, False, False] # note_off / note_on+0 / mixed
is_tempo = False
# 预检
for i, track in enumerate(mid.tracks):
for msg in track:
# print(msg)
if msg.is_meta is not True:
if msg.type == 'note_on' and msg.velocity == 0:
type_[1] = True
elif msg.type == "note_off":
type_[0] = True
if msg.is_meta is True and msg.type == "set_tempo":
is_tempo = True
if is_tempo is not True:
raise Exception("这个mid没有可供计算时间的tempo事件")
if type_[0] is True and type_[1] is True:
type_[2] = True
type_[1] = False
type_[0] = False
print(type_)
bpm = 0
recent_change_bpm = 0
is_change_bpm = False
# 实检
for i, track in enumerate(mid.tracks):
noteOn = []
trackS = []
ticks = 0
for msg in track:
print(msg)
ticks += msg.time
print(ticks)
if msg.is_meta is True and msg.type == "set_tempo":
recent_change_bpm = bpm
bpm = 60000000 / msg.tempo
is_change_bpm = True
if msg.type == 'note_on' and msg.velocity != 0:
noteOn.append([msg, msg.note, ticks])
if type_[1] is True:
if msg.type == 'note_on' and msg.velocity == 0:
for u in noteOn:
index = 0
if u[1] == msg.note:
lastMessage = u[0]
lastTick = u[2]
break
index += 1
print(lastTick)
if is_change_bpm and recent_change_bpm != 0:
trackS.append(NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick,
mid, recent_change_bpm, bpm))
is_change_bpm = False
else:
trackS.append(
NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick,
mid, bpm))
# print(noteOn)
# print(index)
try:
noteOn.pop(index)
except IndexError:
noteOn.pop(index - 1)
print(trackS)
for j in trackS:
print(j)
if __name__ == '__main__':
load(mido.MidiFile("test.mid"))
# ============================
from typing import Literal
from ..constants import x,y,z
# 不要用 没写完
def delay_to_note_blocks(
baseblock: str = "stone",
position_forward: Literal['x','y','z'] = z,
):
"""传入音符,生成以音符盒存储的红石音乐
:param:
baseblock: 中继器的下垫方块
position_forward: 结构延长方向
:return 是否生成成功
"""
from TrimMCStruct import Structure, Block
struct = Structure(
(_sideLength, max_height, _sideLength), # 声明结构大小
)
log = print
startpos = [0,0,0]
# 1拍 x 2.5 rt
for i in notes:
error = True
try:
struct.set_block(
[startpos[0], startpos[1] + 1, startpos[2]],
form_note_block_in_NBT_struct(height2note[i[0]], instrument),
)
struct.set_block(startpos, Block("universal_minecraft", instuments[i[0]][1]),)
error = False
except ValueError:
log("无法放置音符:" + str(i) + "" + str(startpos))
struct.set_block(Block("universal_minecraft", baseblock), startpos)
struct.set_block(
Block("universal_minecraft", baseblock),
[startpos[0], startpos[1] + 1, startpos[2]],
)
finally:
if error is True:
log("无法放置音符:" + str(i) + "" + str(startpos))
struct.set_block(Block("universal_minecraft", baseblock), startpos)
struct.set_block(
Block("universal_minecraft", baseblock),
[startpos[0], startpos[1] + 1, startpos[2]],
)
delay = int(i[1] * speed + 0.5)
if delay <= 4:
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(delay, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
else:
for j in range(int(delay / 4)):
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(4, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
if delay % 4 != 0:
startpos[0] += 1
struct.set_block(
form_repeater_in_NBT_struct(delay % 4, "west"),
[startpos[0], startpos[1] + 1, startpos[2]],
)
struct.set_block(Block("universal_minecraft", baseblock), startpos)
startpos[0] += posadder[0]
startpos[1] += posadder[1]
startpos[2] += posadder[2]

813
Musicreater/main.py Normal file
View File

@@ -0,0 +1,813 @@
# -*- coding: utf-8 -*-
"""
音·创 (Musicreater)
是一款免费开源的针对《我的世界》的midi音乐转换库
Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 音·创 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库根目录下的 License.md
# BUG退散BUG退散 BUG退散BUG退散
# 异常、错误作乱之时 異常、誤りが、困った時は
# 二六字组!万国码合!二六字组!万国码合! グループ!コード#!グループ!コード#!
# 赶快呼叫 程序员Let's Go 直ぐに呼びましょプログラマ レッツゴー!
import math
import os
from typing import List, Literal, Tuple, Union
import mido
from .constants import *
from .exceptions import *
from .subclass import *
from .utils import *
VoidMido = Union[mido.MidiFile, None] # void mido
"""
空Midi类类型
"""
ChannelType = Dict[
int,
Dict[
int,
List[
Union[
Tuple[Literal["PgmC"], int, int],
Tuple[Literal["NoteS"], int, int, int],
Tuple[Literal["NoteE"], int, int],
]
],
],
]
"""
以字典所标记的频道信息类型
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
"""
"""
学习笔记:
tempo: microseconds per quarter note 毫秒每四分音符,换句话说就是一拍占多少毫秒
tick: midi帧
ticks_per_beat: 帧每拍,即一拍多少帧
那么:
tick / ticks_per_beat => amount_of_beats 拍数(四分音符数)
tempo * amount_of_beats => 毫秒数
所以:
tempo * tick / ticks_per_beat => 毫秒数
###########
seconds per tick:
(tempo / 1000000.0) / ticks_per_beat
seconds:
tick * tempo / 1000000.0 / ticks_per_beat
microseconds:
tick * tempo / 1000.0 / ticks_per_beat
gameticks:
tick * tempo / 1000000.0 / ticks_per_beat * 一秒多少游戏刻
"""
@dataclass(init=False)
class MidiConvert:
"""
将Midi文件转换为我的世界内容
"""
midi: VoidMido
"""MidiFile对象"""
midi_music_name: str
"""Midi乐曲名"""
enable_old_exe_format: bool
"""是否启用旧版execute指令格式"""
execute_cmd_head: str
"""execute指令头部"""
channels: ChannelType
"""频道信息字典"""
music_command_list: List[SingleCommand]
"""音乐指令列表"""
music_tick_num: int
"""音乐总延迟"""
progress_bar_command: List[SingleCommand]
"""进度条指令列表"""
def __init__(
self,
midi_obj: VoidMido,
midi_name: str,
enable_old_exe_format: bool = False,
):
"""
简单的midi转换类将midi对象转换为我的世界结构或者包
Parameters
----------
midi_obj: mido.MidiFile 对象
需要处理的midi对象
midi_name: MIDI乐曲名称
此音乐之名
enable_old_exe_format: bool
是否启用旧版(≤1.19)指令格式,默认为否
"""
self.midi: VoidMido = midi_obj
self.midi_music_name: str = midi_name
self.enable_old_exe_format: bool = enable_old_exe_format
self.execute_cmd_head = (
"execute {} ~ ~ ~ "
if enable_old_exe_format
else "execute as {} at @s positioned ~ ~ ~ run "
)
self.progress_bar_command = self.music_command_list = []
self.channels = {}
self.music_tick_num = 0
@classmethod
def from_midi_file(
cls,
midi_file_path: str,
old_exe_format: bool = False,
):
"""
直接输入文件地址将midi文件读入
Parameters
----------
midi_file: str
midi文件地址
enable_old_exe_format: bool
是否启用旧版(≤1.19)指令格式,默认为否
"""
midi_music_name = os.path.splitext(os.path.basename(midi_file_path))[0].replace(
" ", "_"
)
"""文件名,不含路径且不含后缀"""
try:
return cls(
mido.MidiFile(midi_file_path, clip=True),
midi_music_name,
old_exe_format,
)
except (ValueError, TypeError) as E:
raise MidiDestroyedError(f"文件{midi_file_path}损坏:{E}")
except FileNotFoundError as E:
raise FileNotFoundError(f"文件{midi_file_path}不存在:{E}")
# ……真的那么重要吗
# 我又几曾何时,知道祂真的会抛下我
@staticmethod
def inst_to_souldID_withX(
instrumentID: int,
) -> Tuple[str, int]:
"""
返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下
2**( ( msg.note - 60 - X ) / 12 ) 即为MC的音高其中
X的取值随乐器不同而变化
竖琴harp、电钢琴pling、班卓琴banjo、方波bit、颤音琴iron_xylophone 的时候为6
吉他的时候为7
贝斯bass、迪吉里杜管didgeridoo的时候为8
长笛flute、牛铃cou_bell的时候为5
钟琴bell、管钟chime、木琴xylophone的时候为4
而存在一些打击乐器bd(basedrum)、hat、snare没有音域则没有X那么我们返回7即可
Parameters
----------
instrumentID: int
midi的乐器ID
Returns
-------
tuple(str我的世界乐器名, int转换算法中的X)
"""
try:
return PITCHED_INSTRUMENT_TABLE[instrumentID]
except KeyError:
return "note.flute", 5
@staticmethod
def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]:
"""
对于Midi第10通道所对应的打击乐器返回我的世界乐器名
Parameters
----------
instrumentID: int
midi的乐器ID
Returns
-------
tuple(str我的世界乐器名, int转换算法中的X)
"""
try:
return PERCUSSION_INSTRUMENT_TABLE[instrumentID]
except KeyError:
return "note.bd", 7
# 明明已经走了
# 凭什么还要在我心里留下缠绵缱绻
def form_progress_bar(
self,
max_score: int,
scoreboard_name: str,
progressbar_style: tuple = DEFAULT_PROGRESSBAR_STYLE,
) -> List[SingleCommand]:
"""
生成进度条
Parameters
----------
maxscore: int
midi的乐器ID
scoreboard_name: str
所使用的计分板名称
progressbar_style: tuple
此参数详见 ../docs/库的生成与功能文档.md#进度条自定义
Returns
-------
list[SingleCommand,]
"""
pgs_style = progressbar_style[0]
"""用于被替换的进度条原始样式"""
"""
| 标识符 | 指定的可变量 |
|---------|----------------|
| `%%N` | 乐曲名(即传入的文件名)|
| `%%s` | 当前计分板值 |
| `%^s` | 计分板最大值 |
| `%%t` | 当前播放时间 |
| `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位|
"""
perEach = max_score / pgs_style.count("_")
"""每个进度条代表的分值"""
result: List[SingleCommand] = []
if r"%^s" in pgs_style:
pgs_style = pgs_style.replace(r"%^s", str(max_score))
if r"%^t" in pgs_style:
pgs_style = pgs_style.replace(r"%^t", mctick2timestr(max_score))
sbn_pc = scoreboard_name[:2]
if r"%%%" in pgs_style:
result.append(
SingleCommand(
'scoreboard objectives add {}PercT dummy "百分比计算"'.format(sbn_pc),
annotation="新增临时计算用计分板(百分比)",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players set MaxScore {} {}".format(
scoreboard_name, max_score
),
annotation="设定此音乐最大计分",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players set n100 {} 100".format(scoreboard_name),
annotation="设置常量100",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "PercT", scoreboard_name
),
annotation="为临时变量赋值",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} *= n100 {}".format(
sbn_pc + "PercT", scoreboard_name
),
annotation="改变临时变量的单位为百分比(扩大精度)",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} /= MaxScore {}".format(
sbn_pc + "PercT", scoreboard_name
),
annotation="使用临时变量计算百分比",
)
)
# 那是假的
# 一切都并未留下痕迹啊
# 那梦又是多么的真实……
if r"%%t" in pgs_style:
result.append(
SingleCommand(
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(sbn_pc),
annotation="新增临时计算计分板(分)",
)
)
result.append(
SingleCommand(
'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(sbn_pc),
annotation="新增临时计算计分板(秒)",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players set n20 {} 20".format(scoreboard_name),
annotation="设置常量20",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players set n60 {} 60".format(scoreboard_name),
annotation="设置常量60",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "TMinT", scoreboard_name
),
annotation="为临时变量(分)赋值",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} /= n20 {}".format(
sbn_pc + "TMinT", scoreboard_name
),
annotation="将临时变量转换单位为秒(缩减精度)",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "TSecT", sbn_pc + "TMinT"
),
annotation="为临时变量(秒)赋值",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} /= n60 {}".format(
sbn_pc + "TMinT", scoreboard_name
),
annotation="将临时变量(分)转换单位为分(缩减精度)",
)
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores={" + scoreboard_name + "=1..}]"
)
+ "scoreboard players operation @s {} %= n60 {}".format(
sbn_pc + "TSecT", scoreboard_name
),
annotation="将临时变量(秒)确定下来(框定精度区间)",
)
)
for i in range(pgs_style.count("_")):
npg_stl = (
pgs_style.replace("_", progressbar_style[1][0], i + 1)
.replace("_", progressbar_style[1][1])
.replace(r"%%N", self.midi_music_name)
if r"%%N" in pgs_style
else pgs_style.replace("_", progressbar_style[1][0], i + 1).replace(
"_", progressbar_style[1][1]
)
)
if r"%%s" in npg_stl:
npg_stl = npg_stl.replace(
r"%%s",
'"},{"score":{"name":"*","objective":"'
+ scoreboard_name
+ '"}},{"text":"',
)
if r"%%%" in npg_stl:
npg_stl = npg_stl.replace(
r"%%%",
r'"},{"score":{"name":"*","objective":"'
+ sbn_pc
+ r'PercT"}},{"text":"%',
)
if r"%%t" in npg_stl:
npg_stl = npg_stl.replace(
r"%%t",
r'"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},'
r'{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace(
r"{-}", sbn_pc
),
)
result.append(
SingleCommand(
self.execute_cmd_head.format(
r"@a[scores={"
+ scoreboard_name
+ f"={int(i * perEach)}..{math.ceil((i + 1) * perEach)}"
+ r"}]"
)
+ r'titleraw @s actionbar {"rawtext":[{"text":"'
+ npg_stl
+ r'"}]}',
annotation="进度条显示",
)
)
if r"%%%" in pgs_style:
result.append(
SingleCommand(
"scoreboard objectives remove {}PercT".format(sbn_pc),
annotation="移除临时计算计分板(百分比)",
)
)
if r"%%t" in pgs_style:
result.append(
SingleCommand(
"scoreboard objectives remove {}TMinT".format(sbn_pc),
annotation="移除临时计算计分板(分)",
)
)
result.append(
SingleCommand(
"scoreboard objectives remove {}TSecT".format(sbn_pc),
annotation="移除临时计算计分板(秒)",
)
)
self.progress_bar_command = result
return result
def to_music_channels(
self,
) -> ChannelType:
"""
使用金羿的转换思路将midi解析并转换为频道信息字典
Returns
-------
以频道作为分割的Midi信息字典:
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
"""
if self.midi is None:
raise MidiUnboundError(
"你是否正在使用的是一个由 copy_important 生成的MidiConvert对象这是不可复用的。"
)
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
midi_channels: ChannelType = empty_midi_channels()
tempo = mido.midifiles.midifiles.DEFAULT_TEMPO
# 我们来用通道统计音乐信息
# 但是是用分轨的思路的
for track_no, track in enumerate(self.midi.tracks):
microseconds = 0
if not track:
continue
for msg in track:
if msg.time != 0:
microseconds += msg.time * tempo / self.midi.ticks_per_beat / 1000
if msg.is_meta:
if msg.type == "set_tempo":
tempo = msg.tempo
else:
try:
if not track_no in midi_channels[msg.channel].keys():
midi_channels[msg.channel][track_no] = []
except AttributeError as E:
print(msg, E)
if msg.type == "program_change":
midi_channels[msg.channel][track_no].append(
("PgmC", msg.program, microseconds)
)
elif msg.type == "note_on" and msg.velocity != 0:
midi_channels[msg.channel][track_no].append(
("NoteS", msg.note, msg.velocity, microseconds)
)
elif (msg.type == "note_on" and msg.velocity == 0) or (
msg.type == "note_off"
):
midi_channels[msg.channel][track_no].append(
("NoteE", msg.note, microseconds)
)
"""整合后的音乐通道格式
每个通道包括若干消息元素其中逃不过这三种:
1 切换乐器消息
("PgmC", 切换后的乐器ID: int, 距离演奏开始的毫秒)
2 音符开始消息
("NoteS", 开始的音符ID, 力度(响度), 距离演奏开始的毫秒)
3 音符结束消息
("NoteE", 结束的音符ID, 距离演奏开始的毫秒)"""
del tempo, self.channels
self.channels = midi_channels
# [print([print(no,tno,sum([True if i[0] == 'NoteS' else False for i in track])) for tno,track in cna.items()]) if cna else False for no,cna in midi_channels.items()]
return midi_channels
def to_command_list_in_score(
self,
scoreboard_name: str = "mscplay",
max_volume: float = 1.0,
speed: float = 1.0,
) -> Tuple[List[List[SingleCommand]], int, int]:
"""
使用金羿的转换思路将midi转换为我的世界命令列表
Parameters
----------
scoreboard_name: str
我的世界的计分板名称
max_volume: float
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
Returns
-------
tuple( list[list[SingleCommand指令,... ],... ], int指令数量, int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
tracks = []
cmdAmount = 0
maxScore = 0
InstID = -1
self.to_music_channels()
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
for track_no, track in self.channels[i].items():
nowTrack = []
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1])
if SpecialBits
else self.inst_to_souldID_withX(InstID)
)
score_now = round(msg[-1] / float(speed) / 50)
maxScore = max(maxScore, score_now)
mc_pitch = "" if SpecialBits else 2 ** ((msg[1] - 60 - _X) / 12)
nowTrack.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores=({}={})]".format(
scoreboard_name, score_now
)
.replace("(", r"{")
.replace(")", r"}")
)
+ "playsound {} @s ^ ^ ^{} {} {}".format(
soundID, 1 / max_volume - 1, msg[2] / 128, mc_pitch
),
annotation="{}播放{}%{}".format(
mctick2timestr(score_now),
max_volume * 100,
"{}:{}".format(soundID, mc_pitch),
),
),
)
cmdAmount += 1
if nowTrack:
self.music_command_list.extend(nowTrack)
tracks.append(nowTrack)
# print(cmdAmount)
del InstID
self.music_tick_num = maxScore
return (tracks, cmdAmount, maxScore)
def to_command_list_in_delay(
self,
max_volume: float = 1.0,
speed: float = 1.0,
player_selector: str = "@a",
) -> Tuple[List[SingleCommand], int, int]:
"""
使用金羿的转换思路将midi转换为我的世界命令列表并输出每个音符之后的延迟
Parameters
----------
max_volume: float
最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
player_selector: str
玩家选择器,默认为`@a`
Returns
-------
tuple( list[SingleCommand,...], int音乐时长游戏刻, int最大同时播放的指令数量 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels()
tracks = {}
InstID = -1
# cmd_amount = 0
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
# nowChannel = []
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1])
if SpecialBits
else self.inst_to_souldID_withX(InstID)
)
delaytime_now = round(msg[-1] / float(speed) / 50)
try:
tracks[delaytime_now].append(
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{128 / max_volume / msg[2] - 1} {msg[2] / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
)
except KeyError:
tracks[delaytime_now] = [
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{128 / max_volume / msg[2] - 1} {msg[2] / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
]
# cmd_amount += 1
# print(cmd_amount)
del InstID
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
max_multi = 0
for i in range(len(all_ticks)):
max_multi = max(max_multi, len(tracks[all_ticks[i]]))
for j in range(len(tracks[all_ticks[i]])):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
annotation="{}播放{}%{}".format(
mctick2timestr(i), max_volume * 100, ""
),
)
)
self.music_command_list = results
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num, max_multi
def copy_important(self):
dst = MidiConvert(
midi_obj=None,
midi_name=self.midi_music_name,
enable_old_exe_format=self.enable_old_exe_format,
)
dst.music_command_list = [i.copy() for i in self.music_command_list]
dst.progress_bar_command = [i.copy() for i in self.progress_bar_command]
dst.music_tick_num = self.music_tick_num
return dst

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
"""
存放非音·创本体的附加内容(插件?)
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
"ConvertConfig",
]
__author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray"))
from .main import *

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
"""
存放关于文件打包的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import os
import uuid
import zipfile
import datetime
from typing import List, Union, Literal
def compress_zipfile(sourceDir, outFilename, compression=8, exceptFile=None):
"""使用compression指定的算法打包目录为zip文件\n
默认算法为DEFLATED(8),可用算法如下:\n
STORED = 0\n
DEFLATED = 8\n
BZIP2 = 12\n
LZMA = 14\n
"""
zipf = zipfile.ZipFile(outFilename, "w", compression)
pre_len = len(os.path.dirname(sourceDir))
for parent, dirnames, filenames in os.walk(sourceDir):
for filename in filenames:
if filename == exceptFile:
continue
pathfile = os.path.join(parent, filename)
arc_name = pathfile[pre_len:].strip(os.path.sep) # 相对路径
zipf.write(pathfile, arc_name)
zipf.close()
def behavior_mcpack_manifest(
pack_description: str = "",
pack_version: Union[List[int], Literal[None]] = None,
pack_name: str = "",
pack_uuid: Union[str, Literal[None]] = None,
modules_description: str = "",
modules_version: List[int] = [0, 0, 1],
modules_uuid: Union[str, Literal[None]] = None,
):
"""
生成一个我的世界行为包组件的定义清单文件
"""
if not pack_version:
now_date = datetime.datetime.now()
pack_version = [
now_date.year,
now_date.month * 100 + now_date.day,
now_date.hour * 100 + now_date.minute,
]
return {
"format_version": 1,
"header": {
"description": pack_description,
"version": pack_version,
"name": pack_name,
"uuid": str(uuid.uuid4()) if not pack_uuid else pack_uuid,
},
"modules": [
{
"description": modules_description,
"type": "data",
"version": modules_version,
"uuid": str(uuid.uuid4()) if not modules_uuid else modules_uuid,
}
],
}

215
Musicreater/plugin/bdx.py Normal file
View File

@@ -0,0 +1,215 @@
# -*- coding: utf-8 -*-
"""
存放有关BDX结构操作的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import List
from ..constants import x, y, z
from ..subclass import SingleCommand
from .common import bottem_side_length_of_smallest_square_bottom_box
bdx_key = {
"x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"],
"y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"],
"z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"],
}
"""key存储了方块移动指令的数据其中可以用key[x|y|z][0|1]来表示xyz的减或增
而key[][2+]是用来增加指定数目的"""
def bdx_move(axis: str, value: int):
if value == 0:
return b""
if abs(value) == 1:
return bdx_key[axis][0 if value == -1 else 1]
pointer = sum(
[
1 if i else 0
for i in (
value != -1,
value < -1 or value > 1,
value < -128 or value > 127,
value < -32768 or value > 32767,
)
]
)
return bdx_key[axis][pointer] + value.to_bytes(
2 ** (pointer - 2), "big", signed=True
)
def form_command_block_in_BDX_bytes(
command: str,
particularValue: int,
impluse: int = 0,
condition: bool = False,
needRedstone: bool = True,
tickDelay: int = 0,
customName: str = "",
executeOnFirstTick: bool = False,
trackOutput: bool = True,
):
"""
使用指定项目返回指定的指令方块放置指令项
:param command: `str`
指令
:param particularValue:
方块特殊值,即朝向
:0 下 无条件
:1 上 无条件
:2 z轴负方向 无条件
:3 z轴正方向 无条件
:4 x轴负方向 无条件
:5 x轴正方向 无条件
:6 下 无条件
:7 下 无条件
:8 下 有条件
:9 上 有条件
:10 z轴负方向 有条件
:11 z轴正方向 有条件
:12 x轴负方向 有条件
:13 x轴正方向 有条件
:14 下 有条件
:14 下 有条件
注意此处特殊值中的条件会被下面condition参数覆写
:param impluse: `int 0|1|2`
方块类型
0脉冲 1循环 2连锁
:param condition: `bool`
是否有条件
:param needRedstone: `bool`
是否需要红石
:param tickDelay: `int`
执行延时
:param customName: `str`
悬浮字
lastOutput: `str`
上次输出字符串,注意此处需要留空
:param executeOnFirstTick: `bool`
首刻执行(循环指令方块是否激活后立即执行若为False则从激活时起延迟后第一次执行)
:param trackOutput: `bool`
是否输出
:return:str
"""
block = b"\x24" + particularValue.to_bytes(2, byteorder="big", signed=False)
for i in [
impluse.to_bytes(4, byteorder="big", signed=False),
bytes(command, encoding="utf-8") + b"\x00",
bytes(customName, encoding="utf-8") + b"\x00",
bytes("", encoding="utf-8") + b"\x00",
tickDelay.to_bytes(4, byteorder="big", signed=True),
executeOnFirstTick.to_bytes(1, byteorder="big"),
trackOutput.to_bytes(1, byteorder="big"),
condition.to_bytes(1, byteorder="big"),
needRedstone.to_bytes(1, byteorder="big"),
]:
block += i
return block
def commands_to_BDX_bytes(
commands_list: List[SingleCommand],
max_height: int = 64,
):
"""
:param commands: 指令列表(指令, 延迟)
:param max_height: 生成结构最大高度
:return 成功与否,成功返回(True,未经过压缩的源,结构占用大小),失败返回(False,str失败原因)
"""
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
len(commands_list), max_height
)
_bytes = b""
y_forward = True
z_forward = True
now_y = 0
now_z = 0
now_x = 0
for command in commands_list:
_bytes += form_command_block_in_BDX_bytes(
command.command_text,
(1 if y_forward else 0)
if (
((now_y != 0) and (not y_forward))
or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if (
((now_z != 0) and (not z_forward))
or (z_forward and (now_z != _sideLength - 1))
)
else 5
),
impluse=2,
condition=command.conditional,
needRedstone=False,
tickDelay=command.delay,
customName=command.annotation_text,
executeOnFirstTick=False,
trackOutput=True,
)
# (1 if y_forward else 0) if ( # 如果y+则向上,反之向下
# ((now_y != 0) and (not y_forward)) # 如果不是y轴上首个方块
# or (y_forward and (now_y != (max_height - 1))) # 如果不是y轴上末端方块
# ) else ( # 否则即是y轴末端或首个方块
# (3 if z_forward else 2) if ( # 如果z+则向z轴正方向反之负方向
# ((now_z != 0) and (not z_forward)) # 如果不是z轴上的首个方块
# or (z_forward and (now_z != _sideLength - 1)) # 如果不是z轴上的末端方块
# ) else 5 # 否则则要面向x轴正方向
# )
now_y += 1 if y_forward else -1
if ((now_y >= max_height) and y_forward) or ((now_y < 0) and (not y_forward)):
now_y -= 1 if y_forward else -1
y_forward = not y_forward
now_z += 1 if z_forward else -1
if ((now_z >= _sideLength) and z_forward) or (
(now_z < 0) and (not z_forward)
):
now_z -= 1 if z_forward else -1
z_forward = not z_forward
_bytes += bdx_key[x][1]
now_x += 1
else:
_bytes += bdx_key[z][int(z_forward)]
else:
_bytes += bdx_key[y][int(y_forward)]
return (
_bytes,
[
now_x + 1,
max_height if now_x or now_z else now_y,
_sideLength if now_x else now_z,
],
[now_x, now_y, now_z],
)

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
用以生成BDX结构文件的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
"to_BDX_file_in_score",
"to_BDX_file_in_delay"
]
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,220 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import os
import brotli
from ...main import MidiConvert
from ...subclass import SingleCommand
from ..bdx import (bdx_move, commands_to_BDX_bytes,
form_command_block_in_BDX_bytes, x, y, z)
from ..main import ConvertConfig
def to_BDX_file_in_score(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
scoreboard_name: str = "mscplay",
auto_reset: bool = False,
author: str = "Eilles",
max_height: int = 64,
):
"""
将midi以计分播放器形式转换为BDX结构文件
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
scoreboard_name: str
我的世界的计分板名称
auto_reset: bool
是否自动重置计分板
author: str
作者名称
max_height: int
生成结构最大高度
Returns
-------
tuple[int指令数量, int音乐总延迟, tuple[int,]结构大小, tuple[int,]终点坐标]
"""
cmdlist, command_count, max_score = midi_cvt.to_command_list_in_score(
scoreboard_name, data_cfg.volume_ratio, data_cfg.speed_multiplier
)
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.bdx")
),
"w+",
) as f:
f.write("BD@")
_bytes = (
b"BDX\x00" + author.encode("utf-8") + b" & Musicreater\x00\x01command_block\x00"
)
cmdBytes, size, finalPos = commands_to_BDX_bytes(
midi_cvt.music_command_list
+ (
[
SingleCommand(
command="scoreboard players reset @a[scores={"
+ scoreboard_name
+ "="
+ str(max_score + 20)
+ "}] "
+ scoreboard_name,
annotation="自动重置计分板",
)
]
if auto_reset
else []
),
max_height - 1,
)
if data_cfg.progressbar_style:
pgbBytes, pgbSize, pgbNowPos = commands_to_BDX_bytes(
midi_cvt.form_progress_bar(
max_score, scoreboard_name, data_cfg.progressbar_style
),
max_height - 1,
)
_bytes += pgbBytes
_bytes += bdx_move(y, -pgbNowPos[1])
_bytes += bdx_move(z, -pgbNowPos[2])
_bytes += bdx_move(x, 2)
size[0] += 2 + pgbSize[0]
size[1] = max(size[1], pgbSize[1])
size[2] = max(size[2], pgbSize[2])
_bytes += cmdBytes
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.bdx")
),
"ab+",
) as f:
f.write(brotli.compress(_bytes + b"XE"))
return command_count, max_score, size, finalPos
def to_BDX_file_in_delay(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
player: str = "@a",
author: str = "Eilles",
max_height: int = 64,
):
"""
使用method指定的转换算法将midi转换为BDX结构文件
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
player: str
玩家选择器,默认为`@a`
author: str
作者名称
max_height: int
生成结构最大高度
Returns
-------
tuple[int指令数量, int音乐总延迟, tuple[int,]结构大小, tuple[int,]终点坐标]
"""
cmdlist, max_delay = midi_cvt.to_command_list_in_delay(
data_cfg.volume_ratio,
data_cfg.speed_multiplier,
player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.bdx")
),
"w+",
) as f:
f.write("BD@")
_bytes = (
b"BDX\x00" + author.encode("utf-8") + b" & Musicreater\x00\x01command_block\x00"
)
cmdBytes, size, finalPos = commands_to_BDX_bytes(cmdlist, max_height - 1)
if data_cfg.progressbar_style:
scb_name = midi_cvt.midi_music_name[:3] + "Pgb"
_bytes += form_command_block_in_BDX_bytes(
r"scoreboard objectives add {} dummy {}".replace(r"{}", scb_name),
1,
customName="初始化进度条",
)
_bytes += bdx_move(z, 2)
_bytes += form_command_block_in_BDX_bytes(
r"scoreboard players add {} {} 1".format(player, scb_name),
1,
1,
customName="显示进度条并加分",
)
_bytes += bdx_move(y, 1)
pgbBytes, pgbSize, pgbNowPos = commands_to_BDX_bytes(
midi_cvt.form_progress_bar(max_delay, scb_name, data_cfg.progressbar_style),
max_height - 1,
)
_bytes += pgbBytes
_bytes += bdx_move(y, -1 - pgbNowPos[1])
_bytes += bdx_move(z, -2 - pgbNowPos[2])
_bytes += bdx_move(x, 2)
_bytes += form_command_block_in_BDX_bytes(
r"scoreboard players reset {} {}".format(player, scb_name),
1,
customName="置零进度条",
)
_bytes += bdx_move(y, 1)
size[0] += 2 + pgbSize[0]
size[1] = max(size[1], pgbSize[1])
size[2] = max(size[2], pgbSize[2])
size[1] += 1
_bytes += cmdBytes
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.bdx")
),
"ab+",
) as f:
f.write(brotli.compress(_bytes + b"XE"))
return len(cmdlist), max_delay, size, finalPos

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
"""
存放通用的普遍性的插件内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import math
def bottem_side_length_of_smallest_square_bottom_box(total: int, maxHeight: int):
"""给定总方块数量和最大高度,返回所构成的图形外切正方形的边长
:param total: 总方块数量
:param maxHeight: 最大高度
:return: 外切正方形的边长 int"""
return math.ceil(math.sqrt(math.ceil(total / maxHeight)))

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
"""
用以生成函数附加包的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
"to_function_addon_in_score"
]
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import json
import os
import shutil
from typing import Tuple
from ...main import MidiConvert
from ..archive import behavior_mcpack_manifest, compress_zipfile
from ..main import ConvertConfig
def to_function_addon_in_score(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
scoreboard_name: str = "mscplay",
auto_reset: bool = False,
) -> Tuple[int, int]:
"""
将midi以计分播放器形式转换为我的世界函数附加包
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
scoreboard_name: str
我的世界的计分板名称
auto_reset: bool
是否自动重置计分板
Returns
-------
tuple[int指令数量, int音乐总延迟]
"""
cmdlist, maxlen, maxscore = midi_cvt.to_command_list_in_score(
scoreboard_name, data_cfg.volume_ratio, data_cfg.speed_multiplier
)
# 当文件f夹{self.outputPath}/temp/functions存在时清空其下所有项目然后创建
if os.path.exists(f"{data_cfg.dist_path}/temp/functions/"):
shutil.rmtree(f"{data_cfg.dist_path}/temp/functions/")
os.makedirs(f"{data_cfg.dist_path}/temp/functions/mscplay")
# 写入manifest.json
with open(f"{data_cfg.dist_path}/temp/manifest.json", "w", encoding="utf-8") as f:
json.dump(
behavior_mcpack_manifest(
pack_description=f"{midi_cvt.midi_music_name} 音乐播放包MCFUNCTION(MCPACK) 计分播放器 - 由 音·创 生成",
pack_name=midi_cvt.midi_music_name + "播放",
modules_description=f"无 - 由 音·创 生成",
),
fp=f,
indent=4,
)
# 将命令列表写入文件
index_file = open(
f"{data_cfg.dist_path}/temp/functions/index.mcfunction", "w", encoding="utf-8"
)
for i in range(len(cmdlist)):
index_file.write(f"function mscplay/track{i + 1}\n")
with open(
f"{data_cfg.dist_path}/temp/functions/mscplay/track{i + 1}.mcfunction",
"w",
encoding="utf-8",
) as f:
f.write("\n".join([single_cmd.cmd for single_cmd in cmdlist[i]]))
index_file.writelines(
(
"scoreboard players add @a[scores={"
+ scoreboard_name
+ "=1..}] "
+ scoreboard_name
+ " 1\n",
(
"scoreboard players reset @a[scores={"
+ scoreboard_name
+ "="
+ str(maxscore + 20)
+ "..}]"
+ f" {scoreboard_name}\n"
)
if auto_reset
else "",
f"function mscplay/progressShow\n" if data_cfg.progressbar_style else "",
)
)
if data_cfg.progressbar_style:
with open(
f"{data_cfg.dist_path}/temp/functions/mscplay/progressShow.mcfunction",
"w",
encoding="utf-8",
) as f:
f.writelines(
"\n".join(
[
single_cmd.cmd
for single_cmd in midi_cvt.form_progress_bar(
maxscore, scoreboard_name, data_cfg.progressbar_style
)
]
)
)
index_file.close()
if os.path.exists(f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack"):
os.remove(f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack")
compress_zipfile(
f"{data_cfg.dist_path}/temp/",
f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack",
)
shutil.rmtree(f"{data_cfg.dist_path}/temp/")
return maxlen, maxscore

View File

@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
"""
存放附加内容功能
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from dataclasses import dataclass
from typing import Tuple, Union, Literal
from ..constants import DEFAULT_PROGRESSBAR_STYLE
@dataclass(init=False)
class ConvertConfig:
"""
转换通用设置存储类
"""
volume_ratio: float
"""音量比例"""
speed_multiplier: float
"""速度倍率"""
progressbar_style: Union[Tuple[str, Tuple[str, str]], Literal[None]]
"""进度条样式组"""
dist_path: str
"""输出目录"""
def __init__(
self,
output_path: str,
volume: float = 1.0,
speed: float = 1.0,
progressbar: Union[bool, Tuple[str, Tuple[str, str]]] = True,
):
"""
将已经转换好的数据内容指令载入MC可读格式
Parameters
----------
output_path: str
生成内容的输出目录
volume: float
音量比率,范围为(0,1],其原理为在距离玩家 (1 / volume -1) 的地方播放音频
speed: float
速度倍率,注意:这里的速度指的是播放速度倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
progressbar: bool|tuple[str, Tuple[str,]]
进度条,当此参数为 `True` 时使用默认进度条,为其他的**值为真**的参数时识别为进度条自定义参数,为其他**值为假**的时候不生成进度条
"""
self.dist_path = output_path
"""输出目录"""
self.volume_ratio = volume
"""音量比例"""
self.speed_multiplier = speed
"""速度倍率"""
if progressbar:
# 此处是对于仅有 True 的参数和自定义参数的判断
# 改这一段没🐎
if progressbar is True:
self.progressbar_style = DEFAULT_PROGRESSBAR_STYLE
"""进度条样式组"""
else:
self.progressbar_style = progressbar
"""进度条样式组"""
else:
self.progressbar_style = None
"""进度条样式组"""

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
用以生成单个mcstructure文件的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
"to_mcstructure_file_in_delay",
"to_mcstructure_file_in_redstone_CD",
]
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import os
from typing import Literal
from ...exceptions import CommandFormatError
from ...main import MidiConvert
from ..main import ConvertConfig
from ..mcstructure import commands_to_structure,commands_to_redstone_delay_structure
def to_mcstructure_file_in_delay(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
player: str = "@a",
max_height: int = 64,
):
"""
将midi以延迟播放器形式转换为mcstructure结构文件
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
player: str
玩家选择器,默认为`@a`
max_height: int
生成结构最大高度
Returns
-------
tuple[tuple[int,]结构大小, int音乐总延迟]
"""
if midi_cvt.enable_old_exe_format:
raise CommandFormatError("使用mcstructure结构文件导出时不支持旧版本的指令格式。")
cmd_list, max_delay = midi_cvt.to_command_list_in_delay(
data_cfg.volume_ratio,
data_cfg.speed_multiplier,
player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
struct, size, end_pos = commands_to_structure(cmd_list, max_height - 1)
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.mcstructure")
),
"wb+",
) as f:
struct.dump(f)
return size, max_delay
def to_mcstructure_file_in_redstone_CD(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
player: str = "@a",
axis_side: Literal["z+","z-","Z+","Z-","x+","x-","X+","X-"] = "z+",
basement_block: str = "concrete",
):
"""
将midi以延迟播放器形式转换为mcstructure结构文件
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
player: str
玩家选择器,默认为`@a`
axis_side: Literal["z+","z-","Z+","Z-","x+","x-","X+","X-"]
生成结构的延展方向
basement_block: str
结构的基底方块
Returns
-------
tuple[tuple[int,]结构大小, int音乐总延迟]
"""
if midi_cvt.enable_old_exe_format:
raise CommandFormatError("使用mcstructure结构文件导出时不支持旧版本的指令格式。")
cmd_list, max_delay, max_multiple_cmd = midi_cvt.to_command_list_in_delay(
data_cfg.volume_ratio,
data_cfg.speed_multiplier,
player,
)
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
struct, size, end_pos = commands_to_redstone_delay_structure(cmd_list,max_delay,max_multiple_cmd, basement_block, axis_side)
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.mcstructure")
),
"wb+",
) as f:
struct.dump(f)
return size, max_delay

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
"""
用以生成结构附加包的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
"to_mcstructure_addon_in_delay"
]
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import json
import os
import shutil
from TrimMCStruct import Structure
from ...exceptions import CommandFormatError
from ...main import MidiConvert
from ..archive import behavior_mcpack_manifest, compress_zipfile
from ..main import ConvertConfig
from ..mcstructure import commands_to_structure, form_command_block_in_NBT_struct
def to_mcstructure_addon_in_delay(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
player: str = "@a",
max_height: int = 64,
):
"""
将midi以延迟播放器形式转换为mcstructure结构文件后打包成附加包并在附加包中生成相应地导入函数
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
player: str
玩家选择器,默认为`@a`
max_height: int
生成结构最大高度
Returns
-------
tuple[int指令数量, int音乐总延迟]
"""
if midi_cvt.enable_old_exe_format:
raise CommandFormatError("使用mcstructure结构文件导出时不支持旧版本的指令格式。")
command_list, max_delay = midi_cvt.to_command_list_in_delay(
data_cfg.volume_ratio,
data_cfg.speed_multiplier,
player,
)[:2]
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
# 当文件f夹{self.outputPath}/temp/存在时清空其下所有项目,然后创建
if os.path.exists(f"{data_cfg.dist_path}/temp/"):
shutil.rmtree(f"{data_cfg.dist_path}/temp/")
os.makedirs(f"{data_cfg.dist_path}/temp/functions/")
os.makedirs(f"{data_cfg.dist_path}/temp/structures/")
# 写入manifest.json
with open(f"{data_cfg.dist_path}/temp/manifest.json", "w", encoding="utf-8") as f:
json.dump(
behavior_mcpack_manifest(
pack_description=f"{midi_cvt.midi_music_name} 音乐播放包MCSTRUCTURE(MCPACK) 延迟播放器 - 由 音·创 生成",
pack_name=midi_cvt.midi_music_name + "播放",
modules_description=f"无 - 由 音·创 生成",
),
fp=f,
indent=4,
)
# 将命令列表写入文件
index_file = open(
f"{data_cfg.dist_path}/temp/functions/index.mcfunction", "w", encoding="utf-8"
)
struct, size, end_pos = commands_to_structure(command_list, max_height - 1)
with open(
os.path.abspath(
os.path.join(
data_cfg.dist_path,
"temp/structures/",
f"{midi_cvt.midi_music_name}_main.mcstructure",
)
),
"wb+",
) as f:
struct.dump(f)
del struct
if data_cfg.progressbar_style:
scb_name = midi_cvt.midi_music_name[:3] + "Pgb"
index_file.write("scoreboard objectives add {0} dummy {0}\n".format(scb_name))
struct_a = Structure(
(1, 1, 1),
)
struct_a.set_block(
(0, 0, 0),
form_command_block_in_NBT_struct(
r"scoreboard players add {} {} 1".format(player, scb_name),
(0, 0, 0),
1,
1,
alwaysRun=False,
customName="显示进度条并加分",
),
)
with open(
os.path.abspath(
os.path.join(
data_cfg.dist_path,
"temp/structures/",
f"{midi_cvt.midi_music_name}_start.mcstructure",
)
),
"wb+",
) as f:
struct_a.dump(f)
index_file.write(f"structure load {midi_cvt.midi_music_name}_start ~ ~ ~1\n")
pgb_struct, pgbSize, pgbNowPos = commands_to_structure(
midi_cvt.form_progress_bar(max_delay, scb_name, data_cfg.progressbar_style),
max_height - 1,
)
with open(
os.path.abspath(
os.path.join(
data_cfg.dist_path,
"temp/structures/",
f"{midi_cvt.midi_music_name}_pgb.mcstructure",
)
),
"wb+",
) as f:
pgb_struct.dump(f)
index_file.write(f"structure load {midi_cvt.midi_music_name}_pgb ~ ~1 ~1\n")
struct_a = Structure(
(1, 1, 1),
)
struct_a.set_block(
(0, 0, 0),
form_command_block_in_NBT_struct(
r"scoreboard players reset {} {}".format(player, scb_name),
(0, 0, 0),
1,
0,
alwaysRun=False,
customName="重置进度条计分板",
),
)
with open(
os.path.abspath(
os.path.join(
data_cfg.dist_path,
"temp/structures/",
f"{midi_cvt.midi_music_name}_reset.mcstructure",
)
),
"wb+",
) as f:
struct_a.dump(f)
del struct_a, pgb_struct
index_file.write(
f"structure load {midi_cvt.midi_music_name}_reset ~{pgbSize[0] + 2} ~ ~1\n"
)
index_file.write(
f"structure load {midi_cvt.midi_music_name}_main ~{pgbSize[0] + 2} ~1 ~1\n"
)
else:
index_file.write(f"structure load {midi_cvt.midi_music_name}_main ~ ~ ~1\n")
index_file.close()
if os.path.exists(f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack"):
os.remove(f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack")
compress_zipfile(
f"{data_cfg.dist_path}/temp/",
f"{data_cfg.dist_path}/{midi_cvt.midi_music_name}.mcpack",
)
shutil.rmtree(f"{data_cfg.dist_path}/temp/")
return len(command_list), max_delay

View File

@@ -0,0 +1,391 @@
# -*- coding: utf-8 -*-
"""
存放有关MCSTRUCTURE结构操作的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import List, Literal, Tuple
from TrimMCStruct import Block, Structure, TAG_Byte, TAG_Long
from ..constants import x, y, z
from ..subclass import SingleCommand
from .common import bottem_side_length_of_smallest_square_bottom_box
import struct
def antiaxis(axis: Literal['x','z','X','Z']):
return z if axis == x else x
def forward_IER(forward: bool):
return 1 if forward else -1
AXIS_PARTICULAR_VALUE = {
x: {
True: 5,
False: 4,
},
y: {
True: 1,
False: 0,
},
z: {
True: 3,
False: 2,
},
}
def command_statevalue(axis_: Literal['x','y','z','X','Y','Z'],forward_:bool):
return AXIS_PARTICULAR_VALUE[axis_.lower()][forward_]
def form_note_block_in_NBT_struct(
note: int,
coordinate: Tuple[int, int, int],
instrument: str = "note.harp",
powered: bool = False,
):
"""生成音符盒方块
:param note: `int`(0~24)
音符的音高
:param coordinate: `tuple[int,int,int]`
此方块所在之相对坐标
:param instrument: `str`
音符盒的乐器
:param powered: `bool`
是否已被激活
:return Block
"""
return Block(
"minecraft",
"noteblock",
{
"instrument": instrument.replace("note.", ""),
"note": note,
"powered": powered,
},
{
"block_entity_data": {
"note": TAG_Byte(note),
"id": "noteblock",
"x": coordinate[0],
"y": coordinate[1],
"z": coordinate[2],
} # type: ignore
},
)
def form_repeater_in_NBT_struct(delay: int, facing: int):
"""生成中继器方块
:param facing: 朝向:
Z- 北 0
X- 东 1
Z+ 南 2
X+ 西 3
:param delay: 0~3
:return Block()"""
return Block(
"minecraft",
"unpowered_repeater",
{
"repeater_delay": delay,
"direction": facing,
},
)
def form_command_block_in_NBT_struct(
command: str,
coordinate: tuple,
particularValue: int,
impluse: int = 0,
condition: bool = False,
alwaysRun: bool = True,
tickDelay: int = 0,
customName: str = "",
executeOnFirstTick: bool = False,
trackOutput: bool = True,
):
"""
使用指定项目返回指定的指令方块结构
:param command: `str`
指令
:param coordinate: `tuple[int,int,int]`
此方块所在之相对坐标
:param particularValue:
方块特殊值,即朝向
:0 下 无条件
:1 上 无条件
:2 z轴负方向 无条件
:3 z轴正方向 无条件
:4 x轴负方向 无条件
:5 x轴正方向 无条件
:6 下 无条件
:7 下 无条件
:8 下 有条件
:9 上 有条件
:10 z轴负方向 有条件
:11 z轴正方向 有条件
:12 x轴负方向 有条件
:13 x轴正方向 有条件
:14 下 有条件
:14 下 有条件
注意此处特殊值中的条件会被下面condition参数覆写
:param impluse: `int 0|1|2`
方块类型
0脉冲 1循环 2连锁
:param condition: `bool`
是否有条件
:param alwaysRun: `bool`
是否始终执行
:param tickDelay: `int`
执行延时
:param customName: `str`
悬浮字
:param executeOnFirstTick: `bool`
首刻执行(循环指令方块是否激活后立即执行若为False则从激活时起延迟后第一次执行)
:param trackOutput: `bool`
是否输出
:return:str
"""
return Block(
"minecraft",
"command_block"
if impluse == 0
else ("repeating_command_block" if impluse == 1 else "chain_command_block"),
states={"conditional_bit": condition, "facing_direction": particularValue},
extra_data={
"block_entity_data": {
"Command": command,
"CustomName": customName,
"ExecuteOnFirstTick": executeOnFirstTick,
"LPCommandMode": 0,
"LPCondionalMode": False,
"LPRedstoneMode": False,
"LastExecution": TAG_Long(0),
"LastOutput": "",
"LastOutputParams": [],
"SuccessCount": 0,
"TickDelay": tickDelay,
"TrackOutput": trackOutput,
"Version": 25,
"auto": alwaysRun,
"conditionMet": False, # 是否已经满足条件
"conditionalMode": condition,
"id": "CommandBlock",
"isMovable": True,
"powered": False, # 是否已激活
"x": coordinate[0],
"y": coordinate[1],
"z": coordinate[2],
} # type: ignore
},
compability_version=17959425,
)
def commands_to_structure(
commands: List[SingleCommand],
max_height: int = 64,
):
"""
:param commands: 指令列表
:param max_height: 生成结构最大高度
:return 结构类,结构占用大小,终点坐标
"""
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
len(commands), max_height
)
struct = Structure(
(_sideLength, max_height, _sideLength), # 声明结构大小
)
y_forward = True
z_forward = True
now_y = 0
now_z = 0
now_x = 0
for command in commands:
coordinate = (now_x, now_y, now_z)
struct.set_block(
coordinate,
form_command_block_in_NBT_struct(
command=command.command_text,
coordinate=coordinate,
particularValue=(1 if y_forward else 0)
if (
((now_y != 0) and (not y_forward))
or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if (
((now_z != 0) and (not z_forward))
or (z_forward and (now_z != _sideLength - 1))
)
else 5
),
impluse=2,
condition=False,
alwaysRun=True,
tickDelay=command.delay,
customName=command.annotation_text,
executeOnFirstTick=False,
trackOutput=True,
),
)
now_y += 1 if y_forward else -1
if ((now_y >= max_height) and y_forward) or ((now_y < 0) and (not y_forward)):
now_y -= 1 if y_forward else -1
y_forward = not y_forward
now_z += 1 if z_forward else -1
if ((now_z >= _sideLength) and z_forward) or (
(now_z < 0) and (not z_forward)
):
now_z -= 1 if z_forward else -1
z_forward = not z_forward
now_x += 1
return (
struct,
(
now_x + 1,
max_height if now_x or now_z else now_y,
_sideLength if now_x else now_z,
),
(now_x, now_y, now_z),
)
def commands_to_redstone_delay_structure(
commands: List[SingleCommand],
delay_length: int,
max_multicmd_length: int,
base_block: str = "concrete",
axis_: Literal["z+","z-","Z+","Z-","x+","x-","X+","X-"] = "z+",
) -> Tuple[Structure, Tuple[int, int, int], Tuple[int, int, int]]:
"""
:param commands: 指令列表
:param delay_length: 延时总长
:param max_multicmd_length: 最大同时播放的音符数量
:param base_block: 生成结构的基底方块
:param axis_: 生成结构的延展方向
:return 结构类,结构占用大小,终点坐标
"""
if axis_ in ["z+", "Z+"]:
extensioon_direction = z
aside_direction = x
repeater_facing = 2
forward = True
elif axis_ in ["z-", "Z-"]:
extensioon_direction = z
aside_direction = x
repeater_facing = 0
forward = False
elif axis_ in ["x+", "X+"]:
extensioon_direction = x
aside_direction = z
repeater_facing = 3
forward = True
elif axis_ in ["x-", "X-"]:
extensioon_direction = x
aside_direction = z
repeater_facing = 1
forward = False
else:
raise ValueError(f"axis_({axis_}) 参数错误。")
goahead = forward_IER(forward)
struct = Structure(
(round(delay_length/2+0.5+len(commands)) if extensioon_direction == x else max_multicmd_length, 3, round(delay_length/2+0.5+len(commands)) if extensioon_direction == z else max_multicmd_length)
)
pos_now = {x:(0 if forward else struct.size[0]),y:0,z:(0 if forward else struct.size[2])}
first_impluse = True
for cmd in commands:
single_repeater_value = round(cmd.delay / 2) % 4 - 1
additional_repeater = round(cmd.delay / 2)// 4
for i in range(additional_repeater):
struct.set_block(
tuple(pos_now.values()),
Block("minecraft", base_block,),
)
struct.set_block(
(pos_now[x],1,pos_now[z]),
form_repeater_in_NBT_struct(
delay=3,
facing=repeater_facing,
),
)
pos_now[extensioon_direction] += goahead
first_impluse = True
if single_repeater_value >= 0:
struct.set_block(
tuple(pos_now.values()),
Block("minecraft", base_block,),
)
struct.set_block(
(pos_now[x],1,pos_now[z]),
form_repeater_in_NBT_struct(
delay=single_repeater_value,
facing=repeater_facing,
),
)
pos_now[extensioon_direction] += goahead
first_impluse = True
struct.set_block(
(pos_now[x],1,pos_now[z]),
form_command_block_in_NBT_struct(
command=cmd.command_text,
coordinate=(pos_now[x],1,pos_now[z]),
particularValue=command_statevalue(extensioon_direction, forward),
# impluse= (0 if first_impluse else 2),
impluse=0,
condition=False,
alwaysRun=False,
tickDelay=0,
customName=cmd.annotation_text,
),
)
struct.set_block(
(pos_now[x],2,pos_now[z]),
Block("minecraft", "redstone_wire"),
)
pos_now[extensioon_direction] += goahead
first_impluse = False
return struct, struct.size, tuple(pos_now.values())

View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""
存放有关红石音乐生成操作的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from ..exceptions import NotDefineProgramError, ZeroSpeedError
from ..main import MidiConvert
from ..subclass import SingleCommand
# 你以为写完了吗?其实并没有
def to_note_list(
midi_cvt: MidiConvert,
speed: float = 1.0,
) -> list:
"""
使用金羿的转换思路将midi转换为我的世界音符盒所用的音高列表并输出每个音符之后的延迟
Parameters
----------
speed: float
速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
Returns
-------
tuple( list[tuple(str指令, int距离上一个指令的延迟 ),...], int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
midi_channels = (
midi_cvt.to_music_channels() if not midi_cvt.channels else midi_cvt.channels
)
tracks = {}
# 此处 我们把通道视为音轨
for i in midi_channels.keys():
# 如果当前通道为空 则跳过
if not midi_channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
# nowChannel = []
for track_no, track in midi_channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
try:
soundID, _X = (
midi_cvt.perc_inst_to_soundID_withX(InstID)
if SpecialBits
else midi_cvt.inst_to_souldID_withX(InstID)
)
except UnboundLocalError as E:
soundID, _X = (
midi_cvt.perc_inst_to_soundID_withX(-1)
if SpecialBits
else midi_cvt.inst_to_souldID_withX(-1)
)
score_now = round(msg[-1] / float(speed) / 50)
# print(score_now)
try:
tracks[score_now].append(
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg[2] / 128} "
f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
except KeyError:
tracks[score_now] = [
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg[2] / 128} "
f"{2 ** ((msg[1] - 60 - _X) / 12)}"
]
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
(
tracks[all_ticks[i]][j],
(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1] if i != 0 else all_ticks[i]
)
),
)
)
return [results, max(all_ticks)]

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
"""
存放有关Schematic结构生成的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import nbtschematic

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
"""
用以生成Schematic结构的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = [
]
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from ..schematic import *

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
"""
存放有关WebSocket服务器操作的内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import fcwslib
# 这个库有问题,正在检修
class Plugin(fcwslib.Plugin):
async def on_connect(self) -> None:
print('对象已被连接')
await self.send_command('list', callback=self.list)
await self.subscribe('PlayerMessage', callback=self.player_message)
async def on_disconnect(self) -> None:
print('对象停止连接')
async def on_receive(self, response) -> None:
print('已接收非常规回复 {}'.format(response))
async def list(self, response) -> None:
print('已收取指令执行回复 {}'.format(response))
async def player_message(self, response) -> None:
print('已收取玩家事件回复 {}'.format(response))

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
"""
用以启动WebSocket服务器播放的附加功能
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__all__ = []
__author__ = (("金羿", "Eilles Wan"),)
from .main import *

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import fcwslib
from ...main import MidiConvert
from ..main import ConvertConfig
from ...subclass import SingleCommand
def open_websocket_server(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
player: str = "@a",
server_dist: str = "localhost",
server_port: int = 8000,
):
wssever = fcwslib.Server(server=server_dist,port=server_port,debug_mode=False)

383
Musicreater/previous.py Normal file
View File

@@ -0,0 +1,383 @@
# -*- coding: utf-8 -*-
"""
旧版本转换功能以及已经弃用的函数
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import Dict, List, Tuple, Union
from .exceptions import *
from .main import MidiConvert, mido
from .subclass import *
from .utils import *
class ObsoleteMidiConvert(MidiConvert):
"""
我说一句话:
这些破烂老代码能跑得起来就是谢天谢地,你们还指望我怎么样?这玩意真的不会再维护了,我发誓!
"""
def to_command_list_method1(
self,
scoreboard_name: str = "mscplay",
MaxVolume: float = 1.0,
speed: float = 1.0,
) -> list:
"""
使用Dislink Sforza的转换思路将midi转换为我的世界命令列表
:param scoreboard_name: 我的世界的计分板名称
:param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
:return: tuple(命令列表, 命令个数, 计分板最大值)
"""
# :param volume: 音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
tracks = []
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
if not self.midi:
raise MidiUnboundError(
"你是否正在使用的是一个由 copy_important 生成的MidiConvert对象这是不可复用的。"
)
MaxVolume = 1 if MaxVolume > 1 else (0.001 if MaxVolume <= 0 else MaxVolume)
commands = 0
maxscore = 0
tempo = mido.midifiles.midifiles.DEFAULT_TEMPO
# 分轨的思路其实并不好,但这个算法就是这样
# 所以我建议用第二个方法 _toCmdList_m2
for i, track in enumerate(self.midi.tracks):
ticks = 0
instrumentID = 0
singleTrack = []
for msg in track:
ticks += msg.time
if msg.is_meta:
if msg.type == "set_tempo":
tempo = msg.tempo
else:
if msg.type == "program_change":
instrumentID = msg.program
if msg.type == "note_on" and msg.velocity != 0:
nowscore = round(
(ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000)
)
maxscore = max(maxscore, nowscore)
if msg.channel == 9:
soundID, _X = self.perc_inst_to_soundID_withX(instrumentID)
else:
soundID, _X = self.inst_to_souldID_withX(instrumentID)
singleTrack.append(
"execute @a[scores={"
+ str(scoreboard_name)
+ "="
+ str(nowscore)
+ "}"
+ f"] ~ ~ ~ playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg.velocity / 128} "
f"{2 ** ((msg.note - 60 - _X) / 12)}"
)
commands += 1
if len(singleTrack) != 0:
tracks.append(singleTrack)
return [tracks, commands, maxscore]
def _toCmdList_m1(
self,
scoreboardname: str = "mscplay",
volume: float = 1.0,
speed: float = 1.0) -> list:
"""
使用Dislink Sforza的转换思路将midi转换为我的世界命令列表
:param scoreboardname: 我的世界的计分板名称
:param volume: 音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
:return: tuple(命令列表, 命令个数, 计分板最大值)
"""
tracks = []
if volume > 1:
volume = 1
if volume <= 0:
volume = 0.001
commands = 0
maxscore = 0
for i, track in enumerate(self.midi.tracks):
ticks = 0
instrumentID = 0
singleTrack = []
for msg in track:
ticks += msg.time
# print(msg)
if msg.is_meta:
if msg.type == "set_tempo":
tempo = msg.tempo
else:
if msg.type == "program_change":
# print("TT")
instrumentID = msg.program
if msg.type == "note_on" and msg.velocity != 0:
nowscore = round(
(ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000)
)
maxscore = max(maxscore, nowscore)
soundID, _X = self.__Inst2soundID_withX(instrumentID)
singleTrack.append(
"execute @a[scores={" +
str(scoreboardname) +
"=" +
str(nowscore) +
"}" +
f"] ~ ~ ~ playsound {soundID} @s ~ ~{1 / volume - 1} ~ {msg.velocity * (0.7 if msg.channel == 0 else 0.9)} {2 ** ((msg.note - 60 - _X) / 12)}")
commands += 1
if len(singleTrack) != 0:
tracks.append(singleTrack)
return [tracks, commands, maxscore]
# 原本这个算法的转换效果应该和上面的算法相似的
def _toCmdList_m2(
self: MidiConvert,
scoreboard_name: str = "mscplay",
MaxVolume: float = 1.0,
speed: float = 1.0,
) -> tuple:
"""
使用神羽和金羿的转换思路将midi转换为我的世界命令列表
:param scoreboard_name: 我的世界的计分板名称
:param MaxVolume: 音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
:return: tuple(命令列表, 命令个数, 计分板最大值)
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
MaxVolume = 1 if MaxVolume > 1 else (0.001 if MaxVolume <= 0 else MaxVolume)
tracks = []
cmdAmount = 0
maxScore = 0
InstID = -1
self.to_music_channels()
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
if i == 9:
SpecialBits = True
else:
SpecialBits = False
nowTrack = []
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1])
if SpecialBits
else self.inst_to_souldID_withX(InstID)
)
score_now = round(msg[-1] / float(speed) / 50)
maxScore = max(maxScore, score_now)
nowTrack.append(
self.execute_cmd_head.format(
"@a[scores=({}={})]".format(scoreboard_name, score_now)
.replace("(", r"{")
.replace(")", r"}")
)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg[2] / 128} "
f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
cmdAmount += 1
if nowTrack:
tracks.append(nowTrack)
return tracks, cmdAmount, maxScore
def _toCmdList_withDelay_m1(
self: MidiConvert,
MaxVolume: float = 1.0,
speed: float = 1.0,
player: str = "@a",
) -> list:
"""
使用Dislink Sforza的转换思路将midi转换为我的世界命令列表并输出每个音符之后的延迟
:param MaxVolume: 最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
:param player: 玩家选择器,默认为`@a`
:return: 全部指令列表[ ( str指令, int距离上一个指令的延迟 ),...]
"""
tracks = {}
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
if not self.midi:
raise MidiUnboundError(
"你是否正在使用的是一个由 copy_important 生成的MidiConvert对象这是不可复用的。"
)
MaxVolume = 1 if MaxVolume > 1 else (0.001 if MaxVolume <= 0 else MaxVolume)
tempo = mido.midifiles.midifiles.DEFAULT_TEMPO
for i, track in enumerate(self.midi.tracks):
instrumentID = 0
ticks = 0
for msg in track:
ticks += msg.time
if msg.is_meta:
if msg.type == "set_tempo":
tempo = msg.tempo
else:
if msg.type == "program_change":
instrumentID = msg.program
if msg.type == "note_on" and msg.velocity != 0:
now_tick = round(
(ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000)
)
soundID, _X = self.inst_to_souldID_withX(instrumentID)
try:
tracks[now_tick].append(
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg.velocity / 128} "
f"{2 ** ((msg.note - 60 - _X) / 12)}"
)
except KeyError:
tracks[now_tick] = [
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg.velocity / 128} "
f"{2 ** ((msg.note - 60 - _X) / 12)}"
]
results = []
all_ticks = list(tracks.keys())
all_ticks.sort()
for i in range(len(all_ticks)):
if i != 0:
for j in range(len(tracks[all_ticks[i]])):
if j != 0:
results.append((tracks[all_ticks[i]][j], 0))
else:
results.append(
(tracks[all_ticks[i]][j], all_ticks[i] - all_ticks[i - 1])
)
else:
for j in range(len(tracks[all_ticks[i]])):
results.append((tracks[all_ticks[i]][j], all_ticks[i]))
return [results, max(all_ticks)]
def _toCmdList_withDelay_m2(
self: MidiConvert,
MaxVolume: float = 1.0,
speed: float = 1.0,
player: str = "@a",
) -> list:
"""
使用神羽和金羿的转换思路将midi转换为我的世界命令列表并输出每个音符之后的延迟
:param MaxVolume: 最大播放音量,注意:这里的音量范围为(0,1],如果超出将被处理为正确值,其原理为在距离玩家 (1 / volume -1) 的地方播放音频
:param speed: 速度,注意:这里的速度指的是播放倍率,其原理为在播放音频的时候,每个音符的播放时间除以 speed
:param player: 玩家选择器,默认为`@a`
:return: 全部指令列表[ ( str指令, int距离上一个指令的延迟 ),...]
"""
tracks = {}
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
MaxVolume = 1 if MaxVolume > 1 else (0.001 if MaxVolume <= 0 else MaxVolume)
InstID = -1
self.to_music_channels()
results = []
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
if i == 9:
SpecialBits = True
else:
SpecialBits = False
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1])
if SpecialBits
else self.inst_to_souldID_withX(InstID)
)
score_now = round(msg[-1] / float(speed) / 50)
try:
tracks[score_now].append(
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg[2] / 128} "
f"{2 ** ((msg[1] - 60 - _X) / 12)}"
)
except KeyError:
tracks[score_now] = [
self.execute_cmd_head.format(player)
+ f"playsound {soundID} @s ^ ^ ^{1 / MaxVolume - 1} {msg[2] / 128} "
f"{2 ** ((msg[1] - 60 - _X) / 12)}"
]
all_ticks = list(tracks.keys())
all_ticks.sort()
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
(
tracks[all_ticks[i]][j],
(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
)
)
return [results, max(all_ticks)]

279
Musicreater/subclass.py Normal file
View File

@@ -0,0 +1,279 @@
# -*- coding: utf-8 -*-
"""
存储许多非主要的相关类
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from dataclasses import dataclass
from typing import Optional
from .constants import PERCUSSION_INSTRUMENT_LIST
@dataclass(init=False)
class SingleNote:
"""存储单个音符的类"""
instrument: int
"""乐器编号"""
note: int
"""音符编号"""
velocity: int
"""力度/响度"""
start_time: int
"""开始之时 ms"""
duration: int
"""音符持续时间 ms"""
track_no: int
"""音符所处的音轨"""
def __init__(
self,
instrument: int,
pitch: int,
velocity: int,
startTime: int,
lastTime: int,
track_number: int = 0,
):
"""用于存储单个音符的类
:param instrument 乐器编号
:param pitch 音符编号
:param velocity 力度/响度
:param startTime 开始之时(ms)
注:此处的时间是用从乐曲开始到当前的毫秒数
:param lastTime 音符延续时间(ms)"""
self.instrument: int = instrument
"""乐器编号"""
self.note: int = pitch
"""音符编号"""
self.velocity: int = velocity
"""力度/响度"""
self.start_time: int = startTime
"""开始之时 ms"""
self.duration: int = lastTime
"""音符持续时间 ms"""
self.track_no: int = track_number
"""音符所处的音轨"""
@property
def inst(self):
"""乐器编号"""
return self.instrument
@inst.setter
def inst(self, inst_):
self.instrument = inst_
@property
def pitch(self):
"""音符编号"""
return self.note
def __str__(self):
return (
f"Note(inst = {self.inst}, pitch = {self.note}, velocity = {self.velocity}, "
f"startTime = {self.start_time}, lastTime = {self.duration}, )"
)
def __tuple__(self):
return self.inst, self.note, self.velocity, self.start_time, self.duration
def __dict__(self):
return {
"inst": self.inst,
"pitch": self.note,
"velocity": self.velocity,
"startTime": self.start_time,
"lastTime": self.duration,
}
def __eq__(self, other) -> bool:
if not isinstance(other, self.__class__):
return False
return self.__str__() == other.__str__()
@dataclass(init=False)
class SingleCommand:
"""存储单个指令的类"""
command_text: str
"""指令文本"""
conditional: bool
"""执行是否有条件"""
delay: int
"""执行的延迟"""
annotation_text: str
"""指令注释"""
def __init__(
self,
command: str,
condition: bool = False,
tick_delay: int = 0,
annotation: str = "",
):
"""
存储单个指令的类
Parameters
----------
command: str
指令
condition: bool
是否有条件
tick_delay: int
执行延时
annotation: str
注释
"""
self.command_text = command
self.conditional = condition
self.delay = tick_delay
self.annotation_text = annotation
def copy(self):
return SingleCommand(
command=self.command_text,
condition=self.conditional,
tick_delay=self.delay,
annotation=self.annotation_text,
)
@property
def cmd(self) -> str:
"""
我的世界函数字符串(包含注释)
"""
return self.__str__()
def __str__(self) -> str:
"""
转为我的世界函数文件格式(包含注释)
"""
return "#[{cdt}]<{delay}> {ant}\n{cmd}".format(
cdt="CDT" if self.conditional else "",
delay=self.delay,
ant=self.annotation_text,
cmd=self.command_text,
)
def __eq__(self, other) -> bool:
if not isinstance(other, self.__class__):
return False
return self.__str__() == other.__str__()
@dataclass(init=False)
class SingleNoteBox:
"""存储单个音符盒"""
instrument_block: str
"""乐器方块"""
note_value: int
"""音符盒音高"""
annotation_text: str
"""音符注释"""
is_percussion: bool
"""是否为打击乐器"""
def __init__(
self,
instrument_block_: str,
note_value_: int,
percussion: Optional[bool] = None,
annotation: str = "",
):
"""用于存储单个音符盒的类
:param instrument_block_ 音符盒演奏所使用的乐器方块
:param note_value_ 音符盒的演奏音高
:param percussion 此音符盒乐器是否作为打击乐处理
注:若为空,则自动识别是否为打击乐器
:param annotation 音符注释"""
self.instrument_block = instrument_block_
"""乐器方块"""
self.note_value = note_value_
"""音符盒音高"""
self.annotation_text = annotation
"""音符注释"""
if percussion is None:
self.is_percussion = percussion in PERCUSSION_INSTRUMENT_LIST
else:
self.is_percussion = percussion
@property
def inst(self) -> str:
"""获取音符盒下的乐器方块"""
return self.instrument_block
@inst.setter
def inst(self, inst_):
self.instrument_block = inst_
@property
def note(self) -> int:
"""获取音符盒音调特殊值"""
return self.note_value
@note.setter
def note(self, note_):
self.note_value = note_
@property
def annotation(self) -> str:
"""获取音符盒的备注"""
return self.annotation_text
@annotation.setter
def annotation(self, annotation_):
self.annotation_text = annotation_
def copy(self):
return SingleNoteBox(
instrument_block_=self.instrument_block,
note_value_=self.note_value,
annotation=self.annotation_text,
)
def __str__(self) -> str:
return f"Note(inst = {self.inst}, note = {self.note}, )"
def __tuple__(self) -> tuple:
return self.inst, self.note, self.annotation
def __dict__(self) -> dict:
return {
"inst": self.inst,
"note": self.note,
"annotation": self.annotation,
}
def __eq__(self, other) -> bool:
if not isinstance(other, self.__class__):
return False
return self.__str__() == other.__str__()

39
Musicreater/utils.py Normal file
View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
"""
存放主程序所必须的功能性内容
"""
"""
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory
"""
# 睿穆组织 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import Any, Dict
def mctick2timestr(mc_tick: int) -> str:
"""
将《我的世界》的游戏刻计转为表示时间的字符串
"""
return str(int(int(mc_tick / 20) / 60)) + ":" + str(int(int(mc_tick / 20) % 60))
def empty_midi_channels(channel_count: int = 17, staff: Any = {}) -> Dict[int, Any]:
"""
空MIDI通道字典
"""
return dict(
(
i,
(staff.copy() if isinstance(staff, (dict, list)) else staff),
) # 这告诉我们你不能忽略任何一个复制的序列因为它真的我哭死折磨我一整天全在这个bug上了
for i in range(channel_count)
)

174
README.md
View File

@@ -1,115 +1,129 @@
# 音·创 Musicreater
<h1 align="center">
· Musicreater
</h1>
[![Licence: Apache (shields.io)](https://img.shields.io/badge/Licence-Apache-blueviolet)](https://choosealicense.com/licenses/apache-2.0/)
[![Bilibili: 凌云金羿 (shields.io)]( https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-blueviolet)](https://space.bilibili.com/397369002/)
[![Bilibili: 诸葛亮与八卦阵 (shields.io)](https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-blueviolet)](https://space.bilibili.com/604072474)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
<p align="center">
<img width="128" height="128" src="https://gitee.com/TriM-Organization/Musicreater/raw/master/resources/msctIcon.ico">
</img>
</p>
<h3 align="center">一款免费开源的我的世界数字音频转换库</h3>
<p align="center">
<img src="https://forthebadge.com/images/badges/built-with-love.svg">
<a href='https://gitee.com/TriM-Organization/Musicreater'>
<img align="right" src='https://gitee.com/TriM-Organization/Musicreater/widgets/widget_1.svg' alt='Fork me on Gitee'>
</img>
</a>
<p>
### 介绍
[![][Bilibili: 金羿ELS]](https://space.bilibili.com/397369002/)
[![][Bilibili: 诸葛亮与八卦阵]](https://space.bilibili.com/604072474)
[![CodeStyle: black]](https://github.com/psf/black)
[![][python]](https://www.python.org/)
[![][license]](LICENSE)
[![][release]](../../releases)
· Musicreater 是由凌天之云创新应用软件开发团队开发的一款免费开源的 **我的世界基岩版** 音乐制作软件
[![GiteeStar](https://gitee.com/TriM-Organization/Musicreater/badge/star.svg?theme=gray)](https://gitee.com/TriM-Organization/Musicreater/stargazers)
[![GiteeFork](https://gitee.com/TriM-Organization/Musicreater/badge/fork.svg?theme=gray)](https://gitee.com/TriM-Organization/Musicreater/members)
[![GitHub Repo stars](https://img.shields.io/github/stars/TriM-Organization/Musicreater?color=white&logo=GitHub&style=plastic)](https://github.com/TriM-Organization/Musicreater/stargazers)
[![GitHub Repo Forks](https://img.shields.io/github/forks/TriM-Organization/Musicreater?color=white&logo=GitHub&style=plastic)](https://github.com/TriM-Organization/Musicreater/forks)
欢迎加群861684859
简体中文 🇨🇳 | [English🇬🇧](README_EN.md)
### 作者
## 介绍 🚀
金羿 Eilles我的世界基岩版指令师个人开发者B站不知名UP主在校高中生
· 是一个免费开源的针对 **我的世界** MIDI 音乐转换库
诸葛亮与八卦阵 bgArray我的世界基岩版玩家喜欢编程和音乐深圳初一学生
欢迎加群[861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
### 软件架构
## 安装 🔳
软件采用 *Python* 作为第一语言目前还没有使用其他语言辅助使用 *Tkinter* 为图形库
- 使用 pypi
支持 Windows7+ 以及各个支持 Python3.8 Linux
```bash
pip install Musicreater
```
***各位开发人员注意多语言支持请使用函数`_`加载文字如需补充请在简体中文的语言文件(zh-CN.lang)中补充***
- 如果出现错误可以尝试
```bash
pip install -i https://pypi.python.org/simple Musicreater
```
- 升级
### 安装教程
```bash
pip install -i https://pypi.python.org/simple Musicreater --upgrade
```
下载音·创自动安装器将其放在你希望安装音·创的位置运行后将自动安装
- 克隆仓库并安装
```bash
git clone https://gitee.com/TriM-Organization/Musicreater.git
cd Musicreater
python setup.py install
```
提示下载源最好选择2GitHub
以上命令中 `python``pip` 请依照各个环境不同灵活更换可能为`python3``pip3`之类
### 从源代码运行教程
## 文档 📄
#### Windows7+
[生成文件的使用](./docs/%E7%94%9F%E6%88%90%E6%96%87%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.md)
0. [Gitee下载需要登陆](https://gitee.com/EillesWan/Musicreater)
[Github下载](https://github.com/EillesWan/Musicreater)本程序源代码
1. 安装Python 3.8.10
[下载64位Python安装包](https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe)
[下载32位Python安装包](https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe)
2. 以管理员身份运行 补全库.py :
- 点击 开始 菜单搜索 `命令提示符`
- 右键点击 `命令提示符` 左键点击 以管理员身份运行
- 补全库.py 拖拽入开启的窗口按下回车
3. 等待安装完成后双击运行 Musicreater.py
[仓库 API 文档](./docs/%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)
#### Linux
## 作者 ✒
0. 若你没有足够优秀的环境推荐先在终端敲
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3
sudo apt-get install python3-pip
sudo apt-get install git
```
1. 若你足够自信该整的都整了就在你想下载此程序的地方打开终端
```bash
sudo git clone https://gitee.com/EillesWan/Musicreater.git
cd Musicreater
python3 补全库.py
python3 Musicreater.py
```
金羿 Eilles我的世界基岩版指令师个人开发者B 站不知名 UP 江西在校高中生
诸葛亮与八卦阵 bgArray我的世界基岩版玩家喜欢编程和音乐深圳初二学生
### 使用说明
## 致谢 🙏
1. 直接运行就好
2. 看得懂简体中文字的不一定全会用
3. 最好要懂一点点英文
本致谢列表排名无顺序
- 感谢 **昀梦**\<QQ1515399885\> 找出指令生成错误 bug 并指正
- 感谢由 **Charlie_Ping 查理平** 带来的 BDX 文件转换参考以及 MIDI-我的世界对应乐器 参考表格
- 感谢由 **[CMA_2401PT](https://github.com/CMA2401PT)** 为我们的软件开发的一些方面进行指导同时我们参考了他的 BDXworkshop 作为 BDX 结构编辑的参考
- 感谢由 **[Dislink Sforza](https://github.com/Dislink) 断联·斯福尔扎**\<QQ1600515314\> 带来的 midi 音色解析以及转换指令的算法我们将其改编并应用同时感谢他的[网页版转换器](https://dislink.github.io/midi2bdx/)给我们的开发与更新带来巨大的压力和动力让我们在原本一骑绝尘的摸鱼道路上转向开发希望他能考上一个理想的大学
- 感谢 **Touch 偷吃**\<QQ1793537164\> 提供的 BDX 导入测试支持并对程序的改进提供了丰富的意见同时也感谢他的不断尝试新的内容使我们的排错更进一步
- 感谢 **Mono**\<QQ738893087\> 反馈安装时的问题辅助我们找到了视窗操作系统下的兼容性问题感谢其反馈延迟播放器出现的重大问题让我们得以修改全部延迟播放错误尤其感谢他对于我们的软件的大力宣传
- 感谢 **Ammelia 艾米利亚**\<QQ2838334637\> 敦促我们进行新的功能开发并为新功能提出了非常优秀的大量建议以及提供的 BDX 导入测试支持为我们的新结构生成算法提供了大量的实际理论支持
- 感谢 **[神羽](https://gitee.com/snowykami) [SnowyKami](https://github.com/snowyfirefly)** 对我们项目的支持与宣传希望他能考得一所优秀的大学
- 感谢 **指令师\_苦力怕 playjuice123**\<QQ240667197\> 为我们的程序找出错误并提醒我们修复一个一直存在的大 bug
- 感谢 **雷霆**\<QQ3555268519\> 用他那令所有开发者都大为光火的操作方法为我们的程序找出错误并提醒修复 bug
- 感谢 **小埋**\<2039310975\> 反馈附加包生成时缺少描述和标题的问题
### 诸葛亮与八卦阵的说明(不必要)
> 感谢广大群友为此程序提供的测试等支持
>
> 若您对我们有所贡献但您的名字没有显示在此列表中请联系我们
1. 首先这里的提示是给想使用多音色资源包的人的如果你想用就请下载 [神羽资源包神羽自己的链接](https://pan.baidu.com/s/11uoq5zwN7c3rX-98DqVpJg)提取码:ek3t
2. 下载到你自己电脑上某个位置可以不放置于本项目下音色资源包较大可以选取只下载
`神羽资源包_乐器音源的资源包\羽音缭绕-midiout_25.0` 这个文件夹再嫌麻烦的话也可以只下载其中的
`神羽资源包_乐器\音源的资源包\羽音缭绕-midiout_25.0\mcpack(国际版推荐)格式_25.0` 或者
`神羽资源包_乐器\音源的资源包\羽音缭绕-midiout_25.0\zip格式_25.0`
4. 接下来就是关键了*音创*中绑定资源包
首先先打开 *音创*->帮助与疑问->\[神羽资源包位置选择\]选择文件夹... 这时候会跳出选择框
关键来了选择***您下载的`羽音缭绕-midiout_25.0`文件夹或者`mcpack(国际版推荐)格式_25.0``zip格式_25.0`的上级目录***
举个例子我的文件路径是这样的
`L:\shenyu\音源的资源包\羽音缭绕-midiout_25.0`这里面有`神羽资源包_25.0_使用方法.xls`
`mcpack(国际版推荐)格式_25.0``zip格式_25.0`两个文件夹和一个.xls文件而你在音创中
也应该选择这个文件夹**L:\shenyu\音源的资源包\羽音缭绕-midiout_25.0**
6. 如果你想使用音色资源包来制作函数那么解析时你应该用 *音创*->编辑->从midi导入音轨且用新方法解析
然后再使用 *音创*->函数->下面的四个新函数
## 联系 📞
### 致谢
若遇到库中的问题欢迎在[](https://gitee.com/TriM-Organization/Musicreater/issues/new)提出你的 issue
1. 感谢由 [Fuckcraft](https://github.com/fuckcraft) 鸣凤鸽子 带来的我的世界websocket服务器功能
2. 感谢 昀梦\<QQ1515399885\> 找出指令生成错误bug并指正
3. 感谢由 Charlie_Ping 查理平 带来的bdx转换功能
4. 感谢由 CMA_2401PT 带来的 BDXWorkShop 供本程序对于bdx操作的指导
5. 感谢由 Miracle Plume 神羽 \<QQshenyu40403\>带来的羽音缭绕基岩版音色资源包
6. 感谢 Arthur Morgan 对本程序的排错提出了最大的支持
7. 感谢广大群友为此程序提供的测试等支持
8. 若您对我们有所贡献但您的名字没有显示在此列表中请联系我
如果需要与开发组进行交流欢迎加入我们的[开发闲聊 Q ](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
---
### 作者\<*金羿*\>(W-YI)联系方式
此项目并非一个官方 我的世界_Minecraft_项目
1. QQ 2647547478
2. 电邮 EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
3. 微信 WYI_DoctorYI
此项目不隶属或关联于 Mojang Studios 微软
### 作者\<*诸葛亮与八卦阵*\>(bgArray) 联系方式
此项目亦不隶属或关联于 网易
1. QQ 4740437765
Minecraft Mojang Synergies AB 的商标此项目中所有对于我的世界Minecraft等相关称呼均为引用性使用
- 上文提及的 网易 公司指代的是在中国大陆运营我的世界中国版的上海网之易网络科技发展有限公司
NOT AN OFFICIAL MINECRAFT PRODUCT.
NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
[Bilibili: 金羿ELS]: https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-00A1E7?style=for-the-badge
[Bilibili: 诸葛亮与八卦阵]: https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-00A1E7?style=for-the-badge
[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

131
README_EN.md Normal file
View File

@@ -0,0 +1,131 @@
<h1 align="center">
· Musicreater
</h1>
<p align="center">
<img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png" >
</img>
</p>
<h3 align="center">A free open-source library of converting digital music files into <i>Minecraft</i> formats.</h3>
<p align="center">
<img src="https://forthebadge.com/images/badges/built-with-love.svg">
</img>
<p>
[![][Bilibili: Eilles]](https://space.bilibili.com/397369002/)
[![][Bilibili: bgArray]](https://space.bilibili.com/604072474)
[![CodeStyle: black]](https://github.com/psf/black)
[![][python]](https://www.python.org/)
[![][license]](LICENSE)
[![][release]](../../releases)
[![GiteeStar](https://gitee.com/TriM-Organization/Musicreater/badge/star.svg?theme=gray)](https://gitee.com/TriM-Organization/Musicreater/stargazers)
[![GiteeFork](https://gitee.com/TriM-Organization/Musicreater/badge/fork.svg?theme=gray)](https://gitee.com/TriM-Organization/Musicreater/members)
[![GitHub Repo stars](https://img.shields.io/github/stars/TriM-Organization/Musicreater?color=white&logo=GitHub&style=plastic)](https://github.com/TriM-Organization/Musicreater/stargazers)
[![GitHub Repo Forks](https://img.shields.io/github/forks/TriM-Organization/Musicreater?color=white&logo=GitHub&style=plastic)](https://github.com/TriM-Organization/Musicreater/forks)
[简体中文 🇨🇳](README.md) | English🇬🇧
**Notice that the language translation of _Musicreater_ may be a little SLOW.**
## Introduction🚀
Musicreater is a free open-source library used for converting digital music files into formats that could be read in _Minecraft_.
Welcome to join our QQ group: [861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
## Installation 🔳
- Via pypi
```bash
pip install Musicreater
```
- If not work, also try:
```bash
pip install -i https://pypi.python.org/simple Musicreater
```
- Update:
```bash
pip install -i https://pypi.python.org/simple Musicreater --upgrade
```
- Clone repo and Install:
```bash
git clone https://github.com/TriM-Organization/Musicreater.git
cd Musicreater
python setup.py install
```
Commands such as `python``pip` could be changed to some like `python3` or `pip3` according to the difference of platforms.
## Documentation📄
(Not in English yet)
[生成文件的使用](./docs/%E7%94%9F%E6%88%90%E6%96%87%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.md)
[仓库 API 文档](./docs/%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)
### Authors✒
Eilles (金羿)A senior high school student, individual developer, unfamous Bilibili UPer, which knows a little about commands in _Minecraft: Bedrock Edition_
bgArray "诸葛亮与八卦阵": A junior high school student, player of _Minecraft: Bedrock Edition_, which is a fan of music and programming.
## Thanks🙏
This list is not in any order.
- Thank _昀梦_\<QQ1515399885\> for finding and correcting the bugs in the commands that _Musicreater_ generated.
- Thank _Charlie_Ping 查理平_ for the bdx convert function for reference, and the reference chart that's used to convert the mid's instruments into Minecraft's instruments.
- Thank _[CMA_2401PT](https://github.com/CMA2401PT)_ for BDXWorkShop for reference of the .bdx structure's operation, and his guidance in some aspects of our development.
- Thank _[Dislink Sforza](https://github.com/Dislink) 断联·斯福尔扎_ \<QQ1600515314\> for his midi analysis algorithm brought to us, we had adapted it and made it applied in one of our working method; Also, thank him for the [WebConvertor](https://dislink.github.io/midi2bdx/) which brought us so much pressure and power to develop as well as update our projects better, instead of loaf on our project. We hope he can get into a good university as he wantted to!
- Thank _Touch 偷吃_\<QQ1793537164\> for support of debugging and testing program and algorithm, as well his/her suggestions to the improvement of our project
- Thank _Mono_\<QQ738893087\> for reporting problems while installing
- Thank _Ammelia 艾米利亚_\<QQ2838334637\> for urging us to develop new functions, and put forward a lot of excellent suggestions for new functions, as well as the BDX file's importing test support provided, which has given a lot of practical theoretical support for our new Structure Generating Algorithm
- Thank _[神羽](https://gitee.com/snowykami) [SnowyKami](https://github.com/snowyfirefly)_ for supporting and promoting our project. Hope he could get into a good university!
- Thank **指令师\_苦力怕 playjuice123**\<QQ240667197\> for finding bugs within our code, and noticed us to repair a big problem.
- Thank **雷霆**\<QQ3555268519\> for his annoying and provoking operations which may awake some problems within the program by chance and reminding us to repair.
> Thanks for a lot of groupmates' support and help
>
> If you have given contribution but haven't been in the list, please contact us!
## Contact Us📞
Meet problems? Welcome to give out your issue [here](https://github.com/EillesWan/Musicreater/issues/new)!
Want to get in contact of developers? Welcome to join our [Chat QQ group](https://jq.qq.com/?_wv=1027&k=hpeRxrYr).
---
NOT AN OFFICIAL MINECRAFT PRODUCT.
NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
NOT APPROVED BY OR ASSOCIATED WITH NETEASE.
此项目并非一个官方 我的世界_Minecraft_项目
此项目不隶属或关联于 Mojang Studios 微软
此项目亦不隶属或关联于 网易 相关
Minecraft Mojang Synergies AB 的商标此项目中所有对于我的世界Minecraft等相关称呼均为引用性使用
- 上文提及的 网易 公司指代的是在中国大陆运营我的世界中国版的上海网之易网络科技发展有限公司
[Bilibili: Eilles]: https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-00A1E7?style=for-the-badge
[Bilibili: bgArray]: https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-00A1E7?style=for-the-badge
[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

View File

@@ -1,114 +0,0 @@
# Musicreater
[![Licence: Apache (shields.io)](https://img.shields.io/badge/Licence-Apache-blueviolet)](https://choosealicense.com/licenses/apache-2.0/)
[![Bilibili: 凌云金羿 (shields.io)]( https://img.shields.io/badge/Bilibili-%E5%87%8C%E4%BA%91%E9%87%91%E7%BE%BF-blueviolet)](https://space.bilibili.com/397369002/)
[![Bilibili: 诸葛亮与八卦阵 (shields.io)](https://img.shields.io/badge/Bilibili-%E8%AF%B8%E8%91%9B%E4%BA%AE%E4%B8%8E%E5%85%AB%E5%8D%A6%E9%98%B5-blueviolet)](https://space.bilibili.com/604072474)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
### Introduction
Musicreater(·) is an Eilles(*W-YI*)'s app that is used for creating musics in **Minecraft: Bedrock Edition**.
Welcome to join our QQ group: 861684859
### Author
Eilles (金羿)The main author, who developed the most and especially the principal parts of Musicreater, and its predecessors, which has been called as "*Minecraft Function Music Maker*", "*Note Fun Creater*", "*Note World Creater*"(now ,they are united as ***Musicreater***!)
bgArray "诸葛亮与八卦阵": Fix bugs, improve code aesthetics, add new functions, change data format, etc.
### Framework
Using *Python* to develop, using Tkinter as a graphics library.
Support Windows7+ && Linux (that supports Python3.8)
***ATTENTION TO DEVELOPERS!!! TO SUPPORT DIFFERENT LANGUAGES, PLEASE USE CONSTANT `READABLETEXT` TO OUTPUT!!! IF YOU NEED TO SUPPLEMENT, PLEASE ADD THEM IN SIMPLEFIED CHINESE\'S LANGUAGE FILE(zhCN.py), WHEATHER WHAT LANGUAGE YOU USE!!!***
### Installation
Download the *[MSCT Auto Installer]()*, put it in a directory that you want to install *Musicreater* into.
Then run the auto installer and it will help you to install the *Musicreator*
Tips: You'd better choose the 2GitHub download source
### Run with Source Code
#### Windows
0. First, download the source code pack of Musicreater.
[Download from Gitee (Need to Login)](https://gitee.com/EillesWan/Musicreater/repository/archive/master.zip)
[Download from Github](https://github.com/EillesWan/Musicreater/archive/refs/heads/master.zip)
1. Install Python 3.8.10
[Download the 64-bit Python Installer](https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe)
[Download the 32-bit Python Installer](https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe)
2. After completing installation, we need to install the libraries :
- Open "Start Menu" and find `cmd`
- Run `cmd` as Administrator
- Drag "补全库.py" into the opened window and press Enter
3. After completing installationdouble click Musicreater.py to run
#### Linux
0. If you 're not sure whether your environment is good enough, please run these commands on Terminal
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3
sudo apt-get install python3-pip
sudo apt-get install git
```
1. Now if you are confident enough about your runtime environment, open Terminal on the place which you want to download Musicreater, and run these
```bash
sudo git clone https://gitee.com/EillesWan/Musicreater.git
cd Musicreater
python3 补全库.py
python3 Musicreater.py
```
### Instructions
1. Just make u understand the Chinese
2. If u dont understand, u can come to the QQ group or email me to ask questions
3. The English Edition is comming soon.
### Explanation of bgArray 诸葛亮与八卦阵 (unnecessary)
1. First! The tips here are for those who want to use the multi tone resource package, [Shenyu resource package (Shenyu's own link)](https://pan.baidu.com/s/11uoq5zwN7c3rX-98DqVpJg) \(Extraction code: `ek3t`\)
2. Download it to any location on your PC. Note that it does ***not*** need to be placed in the directory where *Musicreater* are. The audio resource package is large, so you can choose to download only:`神羽资源包_乐器音源的资源包\羽音缭绕-midiout_25.0`.
Also, you can download only `神羽资源包_乐器\音源的资源包\羽音缭绕-midiout_25.0\mcpack(国际版推荐)格式_25.0` or
`神羽资源包_乐器\音源的资源包\羽音缭绕-midiout_25.0\zip格式_25.0`.
4. The next step is the most IMPORTANT: to bind the resource package to *Musicreater*
First, open *Musicreater*->Q&A->Select \[MiraclePlumeResourcePack\]... .At this time, in the selection box,
the IMPORTANT step comes, select: ***The directory you downloaded: `羽音缭绕-midiout_25.0`, or also the parent directory `mcpack(国际版推荐)格式_25.0`or`zip格式_25.0`***
For example, my file path is as follows:
`L:\shenyu\音源的资源包\羽音缭绕-midiout_25.0` and in the directory, there are two folders and one .xls file:
`神羽资源包_25.0_使用方法.xls`, `mcpack(国际版推荐)格式_25.0` and `zip格式_25.0`, so in *Musicreater* you should also select this folder: **L:\shenyu\音源的资源包\羽音缭绕-midiout_25.0**
6. If you want to use the Miracle Plume Bedrock Edition Audio Resource Pack to make .mcfunction s, you should use Musicreater -> Edit - > Import audio tracks from MIDI and parse them with a new method, and then use it
Musicreater - > function (package) - > the following four new functions
### Thanks
1. Thank [Fuckcraft](https://github.com/fuckcraft) *(鸣凤鸽子 ,etc)* for the function of Creating the Websocket Server for Minecraft: Bedrock Edition.
- *!! They have given me the rights to directly copy the lib into Musicreater*
2. Thank *昀梦*\<QQ1515399885\> for finding and correcting the bugs in the commands that *Musicreater* Created.
3. Thank *Charlie_Ping 查理平* for bdx convert funtion.
4. Thank *CMA_2401PT* for BDXWorkShop as the .bdx structure's operation guide.
5. Thank *Miracle Plume 神羽* \<QQshenyu40403\> for the Miracle Plume Bedrock Edition Audio Resource Pack
6. Thank *Arthur Morgan* for his/her biggest support for the debugging of Musicreater
7. Thanks for a lot of groupmates who support me and help me to test the program.
8. If you have give me some help but u haven't been in the list, please contact me.
### Contact *Eilles(W-YI)*(金羿)
1. QQ 2647547478
2. E-mail EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
3. WeChat WYI_DoctorYI
### Contact *bgArray*(诸葛亮与八卦阵)
1. QQ 4740437765

8
RSMC_test.py Normal file
View File

@@ -0,0 +1,8 @@
import Musicreater.experiment
print(
Musicreater.experiment.FutureMidiConvertRSNB.from_midi_file(
input("midi路径:"), old_exe_format=False
).to_note_list_in_delay()
)

View File

View File

@@ -1,67 +0,0 @@
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)
long = 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 - long)
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 - long)
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)

View File

@@ -1,40 +0,0 @@
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

View File

@@ -1,24 +0,0 @@
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'}

View File

@@ -1,92 +0,0 @@
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])

View File

@@ -1,133 +0,0 @@
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'}

View File

@@ -1,148 +0,0 @@
# -*- 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:
log("找不到文件或无法读取文件" + 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:
log("找不到文件或无法读取文件" + midfile)
return False
log("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

View File

@@ -1,131 +0,0 @@
import os
import pickle
# import tkinter.filedialog
# from namesConstant import zip_name
# from namesConstant import mcpack_name
import bgArrayLib.namesConstant
import shutil
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:路径文件指示错误
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:
try:
with open(r"./nmcsup/1.pkl", 'rb') as rb:
instrument = list(pickle.load(rb))
print(instrument)
except FileNotFoundError:
return False
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
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()

22
clean_update.py Normal file
View File

@@ -0,0 +1,22 @@
import shutil
import os
from rich.console import Console
from rich.progress import track
console = Console()
def main():
with console.status("Find the full path of .egg-info folder"):
egg_info: list = []
for file in os.listdir():
if file.endswith(".egg-info"):
egg_info.append(file)
console.print(file)
for file in track(["build", "dist", "logs", *egg_info], description="Deleting files"):
if os.path.isdir(file) and os.access(file, os.W_OK):
shutil.rmtree(file)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,281 @@
<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>
**此为开发相关文档内容包括所生成文件结构的详细说明特殊参数的详细解释**
# 库的简单调用
参见[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的格式我们提供了 · 内置的附加组件可以借助 `MidiConvert` 对象转换为相应格式
```python
# 导入 Musicreater
import Musicreater
# 导入附加组件功能
import Musicreater.plugin
# 导入相应的文件格式转换功能
# 转换为函数附加包
import Musicreater.plugin.funpack
# 转换为 BDX 结构文件
import Musicreater.plugin.bdxfile
# 转换为 mcstructure 结构文件
import Musicreater.plugin.mcstructfile
# 转换为结构附加包
import Musicreater.plugin.mcstructpack
# 直接通过 websocket 功能播放(正在开发)
import Musicreater.plugin.websocket
# 定义转换参数
cvt_cfg = Musicreater.plugin.ConvertConfig(
output_path,
volumn, # 音量大小参数
speed, # 速度倍率
progressbar, # 进度条样式组(详见下方)
)
# 懒得写了,等哪天有空写吧,后面的没用,是老的。
```
# 生成文件结构
## 名词解释
|名词|解释|备注|
|--------|-----------|----------|
|指令区|一个用于放置指令系统的区域通常是常加载区|常见于服务器指令系统好友联机房间中|
|指令链|与链式指令方块不同一个指令链通常指代的是一串由某种非链式指令方块作为开头后面连着一串链式指令方块的结构|通常的链都应用于需要单次激活而多指令的简单功能|
|起始块|链最初的那个非链式指令方块|此方块为脉冲方块或重复方块皆可|
|指令系统系统|指令系统通常指的是由一个或多个指令链以及相关红石机构相互配合一同组成的为达到某种特定的功能而构建的整体结构|通常的系统都应用于需要综合调配指令的复杂功能可由多个实现不同功能的模块构成不同系统之间可以相互调用各自的模块|
|游戏刻|游戏的一刻是指我的世界的游戏循环运行一次所占用的时间[详见我的世界中文维基](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$ 轴延伸长度为指令方块数量对于给定高度之商的向下取整结果的平方根的向下取整用数学公式的方式表达则是
$$ MaxZ = \left\lfloor\sqrt{\left\lfloor{\frac{NoC}{MaxH}}\right\rfloor}\right\rfloor $$
其中$MaxZ$ 即生成结构的$Z$轴最大延伸长度$NoC$ 表示链结构中所含指令方块的个数$MaxH$ 表示给定的生成结构的最大高度
我们的结构生成器在生成指令链时将首先以相对坐标系 $(0, 0, 0)$ 即相对原点开始自下向上堆叠高度轴 $Y$ 的长当高度轴达到了限制的高度时便将 $Z$ 轴向正方向堆叠`1`个方块并开始自上向下重新堆叠直至高度轴坐标达到相对为 `0`若当所生成结构的 $Z$ 轴长达到了其最大延伸长度则此结构生成器将反转 $Z$ 轴的堆叠方向直至 $Z$ 轴坐标相对为 `0`如此往复直至指令链堆叠完成
## 播放器
以结构生成的文件可以采用多种方式播放一类播放方式我们称其为**播放器**例如**延迟播放器****计分板播放器**等等以后推出的新的播放器届时也会在此处更新
为什么要设计这么多播放器是为了适应不同的播放环境需要通常情况下一个音乐中含有多个音符音符与音符之间存在间隔这里就产生了不一样的实现音符间时间间隔的方式而不同的应用环境下又会产生不一样的要求接下来将对不同的播放器进行详细介绍
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$ |
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号 $x$ 表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
后四个参数决定了这个音的性质而前两个参数仅仅是为了决定音播放的时间
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$ |
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为0.7倍MIDI指定力度其他则为0.9|
|`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号$x$表示一定的音域偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$ |
其中后四个参数决定了这个音的性质
由于这样的延迟数据是依赖于指令方块的设置项所以使用这种播放器所转换出的结果仅可以存储在包含方块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'))`
*为了避免生成错误请尽量避免使用标识符作为定义样式字符串的其他部分*

View File

@@ -0,0 +1,58 @@
<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>
# 生成文件的使用
*由于先前的 **读我文件**(README.md) 过于冗杂现另辟蹊径来给大家全方位的教程*
*这是本库所生成文件的使用声明不是使用本库的教程若要查看**本库的大致文档**可点击[此处](./%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)若要查看有关文件结构的内容可以点击[此处](./%E7%94%9F%E6%88%90%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E.md)*
## 附加包格式
支持的文件后缀`.MCPACK`
- 计分板播放器
1. 导入附加包
2. 在一个循环方块中输入指令 `function index`
3. 将需要聆听音乐的实体的播放所用计分板设置为 `1`
4. 激活循环方块
5. 若想要暂停播放可以停止循环指令方块的激活状态
6. 若想要重置某实体的播放可以将其播放用的计分板重置
> 其中 步骤三 步骤四 的顺序可以调换
- 延迟播放器
1. 导入附加包
2. 在聊天框输入指令 `function index`
3. 同时激活所生成的循环和脉冲指令方块
> 需要注意的是循环指令方块需要一直激活直到音乐结束
## 结构格式
支持的文件后缀`.MCSTRUCTURE``.BDX`
1. 将结构导入世界
- 延迟播放器
2. 将结构生成的第一个指令方块之模式更改为**脉冲**
3. 激活脉冲方块
4. 若欲重置播放可以停止对此链的激活例如停止区块加载
5. 此播放器不支持暂停
- 计分板播放器
2. 在所生成的第一个指令方块前放置一个循环指令方块其朝向应当对着所生成的第一个方块
3. 在循环指令方块中输入使播放对象的播放用计分板加分的指令延迟为 `0`每次循环增加 `1`
4. 激活循环方块
5. 若想要暂停播放可以停止循环指令方块的激活状态
6. 若想要重置某实体的播放可以将其播放用的计分板重置

View File

@@ -0,0 +1,198 @@
**_注意本文档中的对照表版权归属于音·创作者并按照本仓库根目录下 LICENSE.md 中规定开源_**
**_使用时请遵循规定_**
- 版权所有 © 2023 · 开发者
- Copyright © 2023 all the developers of Musicreater
* 开源相关声明请见 仓库根目录下的 License.md
* Terms & Conditions: License.md in the root directory
· 开发交流群 861684859\
Email TriM-Organization@hotmail.com\
若需转载或借鉴 许可声明请查看仓库根目录下的 License.md
# 乐音乐器
| Midi 乐器值 | 我的世界音符名称 | 我的世界音调偏移参数 |
| ----------- | ------------------- | -------------------- |
| 0 | note.harp | 6 |
| 1 | note.harp | 6 |
| 2 | note.pling | 6 |
| 3 | note.harp | 6 |
| 4 | note.pling | 6 |
| 5 | note.pling | 6 |
| 6 | note.harp | 6 |
| 7 | note.harp | 6 |
| 8 | note.share | 7 |
| 9 | note.harp | 6 |
| 10 | note.didgeridoo | 8 |
| 11 | note.harp | 6 |
| 12 | note.xylophone | 4 |
| 13 | note.chime | 4 |
| 14 | note.harp | 6 |
| 15 | note.harp | 6 |
| 16 | note.bass | 8 |
| 17 | note.harp | 6 |
| 18 | note.harp | 6 |
| 19 | note.harp | 6 |
| 20 | note.harp | 6 |
| 21 | note.harp | 6 |
| 22 | note.harp | 6 |
| 23 | note.guitar | 7 |
| 24 | note.guitar | 7 |
| 25 | note.guitar | 7 |
| 26 | note.guitar | 7 |
| 27 | note.guitar | 7 |
| 28 | note.guitar | 7 |
| 29 | note.guitar | 7 |
| 30 | note.guitar | 7 |
| 31 | note.bass | 8 |
| 32 | note.bass | 8 |
| 33 | note.bass | 8 |
| 34 | note.bass | 8 |
| 35 | note.bass | 8 |
| 36 | note.bass | 8 |
| 37 | note.bass | 8 |
| 38 | note.bass | 8 |
| 39 | note.bass | 8 |
| 40 | note.harp | 6 |
| 41 | note.harp | 6 |
| 42 | note.harp | 6 |
| 43 | note.harp | 6 |
| 44 | note.iron_xylophone | 6 |
| 45 | note.guitar | 7 |
| 46 | note.harp | 6 |
| 47 | note.harp | 6 |
| 48 | note.guitar | 7 |
| 49 | note.guitar | 7 |
| 50 | note.bit | 6 |
| 51 | note.bit | 6 |
| 52 | note.harp | 6 |
| 53 | note.harp | 6 |
| 54 | note.bit | 6 |
| 55 | note.flute | 5 |
| 56 | note.flute | 5 |
| 57 | note.flute | 5 |
| 58 | note.flute | 5 |
| 59 | note.flute | 5 |
| 60 | note.flute | 5 |
| 61 | note.flute | 5 |
| 62 | note.flute | 5 |
| 63 | note.flute | 5 |
| 64 | note.bit | 6 |
| 65 | note.bit | 6 |
| 66 | note.bit | 6 |
| 67 | note.bit | 6 |
| 68 | note.flute | 5 |
| 69 | note.harp | 6 |
| 70 | note.harp | 6 |
| 71 | note.flute | 5 |
| 72 | note.flute | 5 |
| 73 | note.flute | 5 |
| 74 | note.harp | 6 |
| 75 | note.flute | 5 |
| 76 | note.harp | 6 |
| 77 | note.harp | 6 |
| 78 | note.harp | 6 |
| 79 | note.harp | 6 |
| 80 | note.bit | 6 |
| 81 | note.bit | 6 |
| 82 | note.bit | 6 |
| 83 | note.bit | 6 |
| 84 | note.bit | 6 |
| 85 | note.bit | 6 |
| 86 | note.bit | 6 |
| 87 | note.bit | 6 |
| 88 | note.bit | 6 |
| 89 | note.bit | 6 |
| 90 | note.bit | 6 |
| 91 | note.bit | 6 |
| 92 | note.bit | 6 |
| 93 | note.bit | 6 |
| 94 | note.bit | 6 |
| 95 | note.bit | 6 |
| 96 | note.bit | 6 |
| 97 | note.bit | 6 |
| 98 | note.bit | 6 |
| 99 | note.bit | 6 |
| 100 | note.bit | 6 |
| 101 | note.bit | 6 |
| 102 | note.bit | 6 |
| 103 | note.bit | 6 |
| 104 | note.harp | 6 |
| 105 | note.banjo | 6 |
| 106 | note.harp | 6 |
| 107 | note.harp | 6 |
| 108 | note.harp | 6 |
| 109 | note.harp | 6 |
| 110 | note.harp | 6 |
| 111 | note.guitar | 7 |
| 112 | note.harp | 6 |
| 113 | note.bell | 4 |
| 114 | note.harp | 6 |
| 115 | note.cow_bell | 5 |
| 116 | note.bd | 7 |
| 117 | note.bass | 8 |
| 118 | note.bit | 6 |
| 119 | note.bd | 7 |
| 120 | note.guitar | 7 |
| 121 | note.harp | 6 |
| 122 | note.harp | 6 |
| 123 | note.harp | 6 |
| 124 | note.harp | 6 |
| 125 | note.hat | 7 |
| 126 | note.bd | 7 |
| 127 | note.snare | 7 |
# 打击乐器
| Midi 打击乐器值 | 我的世界音符名称 | 我的世界音调偏移参数 |
| --------------- | ------------------- | -------------------- |
| 34 | note.bd | 7 |
| 35 | note.bd | 7 |
| 36 | note.hat | 7 |
| 37 | note.snare | 7 |
| 38 | note.snare | 7 |
| 39 | note.snare | 7 |
| 40 | note.hat | 7 |
| 41 | note.snare | 7 |
| 42 | note.hat | 7 |
| 43 | note.snare | 7 |
| 44 | note.snare | 7 |
| 45 | note.bell | 4 |
| 46 | note.snare | 7 |
| 47 | note.snare | 7 |
| 48 | note.bell | 4 |
| 49 | note.hat | 7 |
| 50 | note.bell | 4 |
| 51 | note.bell | 4 |
| 52 | note.bell | 4 |
| 53 | note.bell | 4 |
| 54 | note.bell | 4 |
| 55 | note.bell | 4 |
| 56 | note.snare | 7 |
| 57 | note.hat | 7 |
| 58 | note.chime | 4 |
| 59 | note.iron_xylophone | 6 |
| 60 | note.bd | 7 |
| 61 | note.bd | 7 |
| 62 | note.xylophone | 4 |
| 63 | note.xylophone | 4 |
| 64 | note.xylophone | 4 |
| 65 | note.hat | 7 |
| 66 | note.bell | 4 |
| 67 | note.bell | 4 |
| 68 | note.hat | 7 |
| 69 | note.hat | 7 |
| 70 | note.flute | 5 |
| 71 | note.flute | 5 |
| 72 | note.hat | 7 |
| 73 | note.hat | 7 |
| 74 | note.xylophone | 4 |
| 75 | note.hat | 7 |
| 76 | note.hat | 7 |
| 77 | note.xylophone | 4 |
| 78 | note.xylophone | 4 |
| 79 | note.bell | 4 |
| 80 | note.bell | 4 |

135
example.py Normal file
View File

@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
# 伶伦 开发交流群 861684859
"""
音·创 (Musicreater) 演示程序
是一款免费开源的针对《我的世界》的midi音乐转换库
Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者
Copyright © 2023 all the developers of Musicreater
开源相关声明请见 ./License.md
Terms & Conditions: ./License.md
"""
import os
import Musicreater
from Musicreater.plugin import ConvertConfig
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
from Musicreater.plugin.funcpack import to_function_addon_in_score
from Musicreater.plugin.mcstructpack import to_mcstructure_addon_in_delay
# 获取midi列表
midi_path = input(f"请输入MIDI路径")
# 获取输出地址
out_path = input(f"请输入输出路径:")
# 选择输出格式
fileFormat = int(input(f"请输入输出格式[BDX(1) 或 MCPACK(0)]").lower())
playerFormat = int(input(f"请选择播放方式[计分板(1) 或 延迟(0)]").lower())
# 真假字符串判断
def bool_str(sth: str) -> bool:
try:
return bool(float(sth))
except ValueError:
if str(sth).lower() == "true":
return True
elif str(sth).lower() == "false":
return False
else:
raise ValueError("布尔字符串啊?")
if os.path.exists("./demo_config.json"):
import json
prompts = json.load(open("./demo_config.json", "r", encoding="utf-8"))
else:
prompts = []
# 提示语 检测函数 错误提示语
for args in [
(
f"输入音量:",
float,
),
(
f"输入播放速度:",
float,
),
(
f"是否启用进度条:",
bool_str,
),
(
f"计分板名称:",
str,
)
if playerFormat == 1
else (
f"玩家选择器:",
str,
),
(
f"是否自动重置计分板:",
bool_str,
)
if playerFormat == 1
else (),
(
f"作者名称:",
str,
)
if fileFormat == 1
else (),
()
if playerFormat == 1
else (
f"最大结构高度:",
int,
),
]:
if args:
prompts.append(args[1](input(args[0])))
print(f"正在处理 {midi_path} ")
cvt_mid = Musicreater.MidiConvert.from_midi_file(midi_path, old_exe_format=False)
cvt_cfg = ConvertConfig(out_path, *prompts[:3])
print(
" 指令总长:{},最高延迟:{}".format(
*(
to_function_addon_in_score(cvt_mid, cvt_cfg, *prompts[3:])
if playerFormat == 1
else to_mcstructure_addon_in_delay(cvt_mid, cvt_cfg, *prompts[3:])
)
)
if fileFormat == 0
else " 指令总长:{},最高延迟:{},结构大小{},终点坐标{}".format(
*(
to_BDX_file_in_score(cvt_mid, cvt_cfg, *prompts[3:])
if playerFormat == 1
else to_BDX_file_in_delay(cvt_mid, cvt_cfg, *prompts[3:])
)
)
)
exitSth = input("回车退出").lower()
if exitSth == "record":
import json
with open("./demo_config.json", "w", encoding="utf-8") as f:
json.dump(prompts, f)
elif exitSth == "delrec":
os.remove("./demo_config.json")

13
example_futureFunction.py Normal file
View File

@@ -0,0 +1,13 @@
import Musicreater.experiment
import Musicreater.plugin
import Musicreater.plugin.mcstructpack
print(
Musicreater.plugin.mcstructpack.to_mcstructure_addon_in_delay(
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(
input("输出路径:"),
volume=1
),
)
)

13
example_mcstructure.py Normal file
View File

@@ -0,0 +1,13 @@
import Musicreater
import Musicreater.plugin
import Musicreater.plugin.mcstructfile
print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(
input("输出路径:"),
volume=1
),
)
)

View File

@@ -0,0 +1,13 @@
import Musicreater
import Musicreater.plugin
import Musicreater.plugin.mcstructfile
print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_redstone_CD(
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(
input("输出路径:"),
volume=1
),
)
)

View File

@@ -1,170 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
# 统计致命三级错误2个---未解决警告二级错误2个语法一级错误17个
__version__ = '0.0.1'
__all__ = []
__author__ = 'Fuckcraft <https://gitee.com/fuckcraft>'
'''
Fuckcraft Websocket Library (FCWSLIB)
A library to develop minecraft websocket server easily.
Copyright (C) 2021 Fuckcraft
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
'''
from main import *
# import os
import json
import uuid
# import logging
import asyncio
import time
import websockets
# 写这段代码的时候,只有我和上帝知道这段代码是干什么的。
# 现在只有上帝知道。
# ----
# 没毛病,我讨厌两种人:一种是要我写注释的人,一种是给我代码看但没有写注释的人。
# 此函数用于向 Minecraft 订阅请求
async def subscribe(websocket, event_name):
"""
参数:
: websocket : websocket 对象 :
: event_name : 需要订阅的请求 :
返回:
None
"""
response = {
'body': {
'eventName': str(event_name) # 示例PlayerMessage
},
'header': {
'requestId': str(uuid.uuid4()),
'messagePurpose': 'subscribe',
'version': 1,
'messageType': 'commandRequest'
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 此函数用于向 Minecraft 消除订阅请求
async def unsubscribe(webscket):
"""
参数:
: websocket : websocket 对象 :
: event_name : 需要消除订阅的请求 :
返回:
None
"""
print(webscket)
response = {
"body": {
"eventName": str(event_name) # PlayerMessage
},
"header": {
"requestId": str(uuid.uuid4()),
"messagePurpose": "unsubscribe",
"version": 1,
"messageType": "commandRequest"
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 此函数用于向 Minecraft 执行命令
async def send_command(websocket, command):
"""
参数:
: websocket : websocket 对象 :
: command : 执行的命令 :
返回:
None
"""
response = {
'body': {
'origin': {
'type': 'player'
},
'commandLine': str(command),
'version': 1
},
'header': {
'requestId': str(uuid.uuid4()),
'messagePurpose': 'commandRequest',
'version': 1,
'messageType': 'commandRequest'
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 此函数用于向 Minecraft 发送消息
async def tellraw(websocket, message):
"""
参数:
: websocket : websocket 对象 :
: message : 发送的消息 :
返回:
None
"""
command = {
'rawtext': [
{
'text': '[{}] {}'.format(time.asctime(), message)
}
]
}
# 增加 json 可读性
# command = json.dumps(command, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
command = json.dumps(command)
command = 'tellraw @a {}'.format(command)
await send_command(websocket, command)
def run_server(function):
# 修改 ip 地址和端口
start_server = websockets.serve(function, 'localhost', 8080)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

View File

@@ -1,160 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
__version__ = '0.0.1'
__all__ = ['run_server', 'subscribe', 'unsubscribe', 'send_command', 'tellraw']
__author__ = 'Fuckcraft <https://gitee.com/fuckcraft>'
'''
Fuckcraft Websocket Library (FCWSLIB)
A library to develop minecraft websocket server easily.
Copyright (C) 2021 Fuckcraft
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
'''
import os
import json
import uuid
import logging
import asyncio
import time
import websockets
# 写这段代码的时候,只有我和上帝知道这段代码是干什么的。
# 现在只有上帝知道。
# 此函数用于向 Minecraft 订阅请求
async def subscribe(websocket, event_name):
'''
输入:
: websocket : websocket 对象 :
: event_name : 需要订阅的请求 :
输出:
None
'''
response = {
'body': {
'eventName': str(event_name) # 示例PlayerMessage
},
'header': {
'requestId': str(uuid.uuid4()),
'messagePurpose': 'subscribe',
'version': 1,
'messageType': 'commandRequest'
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 此函数用于向 Minecraft 消除订阅请求
async def unsubscribe(webscket):
'''
输入:
: websocket : websocket 对象 :
: event_name : 需要消除订阅的请求 :
输出:
None
'''
response = {
"body": {
"eventName": str(event_name) # 示例PlayerMessage
},
"header": {
"requestId": str(uuid.uuid4()),
"messagePurpose": "unsubscribe",
"version": 1,
"messageType": "commandRequest"
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 我个人不负责这块的质量,因为他们逼迫我违心的写了这段代码
# 此函数用于向 Minecraft 执行命令
async def send_command(websocket, command):
'''
输入:
: websocket : websocket 对象 :
: command : 执行的命令 :
输出:
None
'''
response = {
'body': {
'origin': {
'type': 'player'
},
'commandLine': str(command),
'version': 1
},
'header': {
'requestId': str(uuid.uuid4()),
'messagePurpose': 'commandRequest',
'version': 1,
'messageType': 'commandRequest'
}
}
# 增加 json 的可读性
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
response = json.dumps(response)
await websocket.send(response)
# 此函数用于向 Minecraft 发送消息
async def tellraw(websocket, message):
'''
输入:
: websocket : websocket 对象 :
: message : 发送的消息 :
输出:
None
'''
command = {
'rawtext':[
{
'text':'[{}] {}'.format(time.asctime(), message)
}
]
}
# 增加 json 可读性
# command = json.dumps(command, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
command = json.dumps(command)
command = 'tellraw @a {}'.format(command)
await send_command(websocket, command)
def run_server(function):
# 修改 ip 地址和端口
start_server = websockets.serve(function, 'localhost', 8080)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

View File

@@ -1,5 +0,0 @@
zh-CN
简体中文 中国大陆
Simplified Chinese, Chinese Mainland
简体中文 中国大陆

View File

@@ -1,99 +0,0 @@
# -*- coding:utf-8 -*-
'''此功能已废弃'''
# W-YI 金羿
# QQ 2647547478
# 音·创 开发交流群 861684859
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
# 版权所有 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
# 若需转载或借鉴 请附作者
"""
Copyright 2022 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# 代码写的并非十分的漂亮还请大佬多多包涵本软件源代码依照Apache软件协议公开
# -----------------------------分割线-----------------------------
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
# 统计致命三级错误0个警告二级错误0个语法一级错误12个
# 目前我的Pycharm并没有显示任何错误有错误可以向
# bgArray 诸葛亮与八卦阵
# QQ 474037765 或最好加入:音·创 开发交流群 861684859
# ------------------------- split line-----------------------------
# Zhuge Liang and Bagua array help to modify the grammar date: -- January 19, 2022
# Statistics: fatal (Level 3) errors: 0; Warning (Level 2) errors: 15; Syntax (Level 1) error: 597
# At present, my Pycham does not display any errors. If there are errors, you can report them to me
# Bgarray Zhuge Liang and Bagua array
# QQ 474037765 or better join: Musicreater development exchange group 861684859
# ------------------------- split line-----------------------------
# 下面为正文
# 将程序中用双引号""括起来的字符串
# 转为字符串列表 list[str, str, ...]
# 方便进行语言翻译支持。
import sys
startWith = 0
def __main__():
textList = []
for fileName in sys.argv[1:]:
print('读取文件: {}'.format(fileName))
fileText = []
for line in open(fileName, 'r', encoding='utf-8'):
while line.count('"') >= 2:
# 只有上帝看得懂我在写什么。
if line[
line.index('"'):2 + line[line.index('"') + 1:].index('"') + len(line[:line.index('"')])] in textList:
thisText = textList.index(
line[line.index('"'):2 + line[line.index('"') + 1:].index('"') + len(line[:line.index('"')])])
else:
thisText = len(textList)
textList.append(
line[line.index('"'):2 + line[line.index('"') + 1:].index('"') + len(line[:line.index('"')])])
line = line.replace(
line[line.index('"'):2 + line[line.index('"') + 1:].index('"') + len(line[:line.index('"')])],
'READABLETEXT[{}]'.format(thisText + startWith)
)
fileText.append(line)
open(fileName + '_C', 'w', encoding='utf-8').writelines(fileText)
outFile = open('lang__.py', 'w', encoding='utf-8')
outFile.write('''# -*- coding:utf-8 -*-
# 由金羿翻译工具生成字符串列表
# 请在所需翻译文件前from 此文件 import READABLETEXT
READABLETEXT = {
''')
for i in range(len(textList)):
outFile.write(" {}:{},\n".format(i + startWith, textList[i]))
outFile.write('}')
outFile.close()
if __name__ == '__main__':
__main__()

View File

@@ -1,180 +0,0 @@
# -*- coding:utf-8 -*-
# 由金羿翻译工具生成字符串列表
# 请在所需翻译的文件前from 此文件 import READABLETEXT
READABLETEXT = {
'Translator': (("Eilles Wan (金羿)", True),),
# 此处是语言翻译者列表,其中每个元组第一项为显示文本,第二项为此文本是否为开发者名字
0: "ERROR❌",
1: "TIPS❗",
2: "Clearing log(this wont be in the file)",
3: "Could not clear the temporary files or logs",
4: "saved",
5: "New Musicreater Project",
6: "Select old-type project",
7: "Select Musicreater Project",
8: "Cant open:{}, please check if youve entered the right name",
9: "Musicreat - About",
10: "Musicreater",
11: "Ver. {}",
12: """Team-Ryoun for Minecraft\n×\nTeam-Ryoun for Software Development""",
13: "OK",
14: "Inpute Notes",
15: (("- Developers -", False),
("Eilles Wan (金羿)", True), ("EillesWan@outlook.com", False), ("QQ 2647547478", False),
("bgArray “诸葛亮与八卦阵”", True), ("QQ 474037765", False)),
# 此处是开发者列表,其中每个元组第一项为显示文本,第二项为此文本是否为开发者名字
16: "- Translators -",
# 17:"",
18: "QQ Group: 861684859",
19: "Musicreater - Help",
20: "Select sound file",
21: "Select MIDI file",
22: "Select NoteText file",
23: "Get Note info",
24: "Write in Note info: {}",
25: "Select generating file",
26: "Select generating folder",
27: "Select generating .mcpack file",
28: "Input position info",
29: "Select generating world folder",
30: "Select generating Function Pack",
31: "Select .mcfunction file ",
32: "Select .bdx file ",
33: "DONE✔",
34: "Input playing rate",
35: "Generating",
36: "Select a world folder",
37: "Make sure",
38: "Generate .RyStruct file",
39: "FAILED❌",
40: "Report message inpution",
41: "Musicreater - {}",
42: "ExecutingEntityName: {}",
43: "ScoreboardName: {}",
44: "Instrument: {}",
45: "TrackName: {}",
46: "PackName: {}",
47: "MusicTitle: {}",
48: "IsRepeat?: {}",
49: "Player'sTargetSelector: {}",
50: "Modify Main Option",
51: "Modify Track Option",
52: "Default Instrument: Enter English\n",
53: "Open...",
54: "Open Old Project...",
55: "Save",
56: "Save as...",
57: "Exit",
58: "File",
59: "Load tracks from sound",
60: "Load tracks from Midi",
61: "Load tracks from Text",
62: "Input notes to track",
63: "Edit",
64: "Generate file...",
65: "Generate function pack...",
66: "Generate .mcpack file...",
67: "Functions(Pack)",
68: "Save music as blocks into a map",
69: "Save music as blocks into a exist map...",
70: "Save music as commands into a map",
71: "Save music as commands into a exist map...",
72: "Save music as notebox into a map",
73: "Save music as notebox into a exist map...",
74: "World",
75: "Generate a function that fits current music...",
76: "Export selected track as commands in .bdx...",
77: "Export .bdx file from map...",
78: "Export .RyStruct file from map...",
79: "Load functions into a world...",
80: "Separate long .mcfunction file into small ones and set them into a world as a chain...",
81: "Additional Functions",
82: "Show generating result",
83: "Set a websocket server on localhost:8080 and play the selected track",
84: "Experimental Functions",
85: "Clear log file",
86: "Clear save file(obsolete)",
87: "Help",
88: "About",
89: "Send a bug report",
90: "Q&A",
91: "Main Options",
92: "Export music as .BDX...",
93: "请输入指令链生成最高相对高度(≥5)",
94: "❌You should input a number which is not lower then 4, please reinput again.",
95: "Structure",
96: "Reset Main Options",
97: "Track Options",
# 98:"",
# 99:"",
# 100:"",
# 101:"",
102: "Delete Selected Track",
# 103:"",
# 104:"",
105: "Error with finding or reading file😢{}",
106: "Project is unsaved, save before close?",
107: "Saved in: {}",
108: ("Musicreater 0.0.X Project","Musicreater 0.1+ Project","Musicreater 0.1+ TESTver Project"),
109: "Any Type",
110: "NoteFunCreater Project",
111: "MMFM (V0.0.6) Project",
112: "All Types",
113: ".MP3 file(piano sound)",
114: "Midi file",
115: "Text file",
116: "Position Inpution",
117: "Format Error❌, please Reinput!",
118: ".MCFUNCTION",
119: "The position of the ChainCB for execution:",
# 120: "",
121: "您的函数文件不大于一万条指令,无需进行分割操作。",
122: "请输入执行链生成相对坐标:",
123: "FastBuilder Structure",
124: "Done!\n{}",
125: "一秒,音乐走几拍?",
126: "按下确认后在游戏中使用connect指令连接localhost:8080即可播放",
127: "请输入区域选择的开始坐标:",
128: "请输入区域选择的结束坐标:",
129: "Whether air block remain when export?",
130: "Musicreater Structure",
131: "Done😃\n{}",
132: "Failed❌\n{}\n{}",
133: "Have not developed yet...",
134: "Your name",
135: "Your contact",
136: "Your description of Problem",
137: "Log file will be cleared when you exit.",
138: "Log file will NOT be cleared when you exit.",
139: "修改包名",
140: "修改音乐标题",
141: "修改玩家选择器\n注意!要加上中括号“[]”",
142: "修改本音轨的执行实体名",
143: "修改本音轨所用的积分板",
144: "修改本音轨所用乐器",
145: "您输入的乐器并非游戏内置乐器,是否继续用您输入的字符作为乐器?",
146: "修改本音轨生成的文件名",
# -----2022.1.25更新
147: "生成新文件至...",
148: "从midi导入音轨且用新方法解析",
149: "Open New: Musicreater Project...",
150: "保存为新项目",
151: "另存为新项...",
152: "(开发调试)关闭本次日志记录",
153: "生成新函数包至...",
154: "生成新函数附加包文件至...",
155: "生成新函数附加包文件,并将神羽资源包以散包形式放置至...",
156: "Select [MiraclePlumeResourcePack]...",
157: "没有路径文件(.rpposi文件)请仔细阅读Readme或先试用帮助与疑问->[神羽资源包位置选择]:选择文件夹... 方法添加路径文件吧!",
158: "有路径文件(.rpposi文件)但路径指示错误请仔细阅读Readme或先用帮助与疑问->[神羽资源包位置选择]:选择文件夹... 更改路径!",
159: "更改路径文件(.rpposi文件)成功!!",
160: "从midi导入音轨且用类方法解析",
161: "打开 类方法: 音·创项目...",
162: "保存为类方法项目",
163: "另存为类方法项...",
}

View File

@@ -1,203 +0,0 @@
# -*- coding:utf-8 -*-
'''对于音·创的语言支持兼语言文件编辑器'''
"""
Copyright 2022 Team-Ryoun
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
DEFAULTLANGUAGE = 'zh-CN'
LANGUAGELIST = {
# 第一个是语言的中文名称和地区
# 第二个是语言的英文名称和地区
# 第三个是语言的本地名称和地区
'zh-CN': (
"简体中文 中国大陆",
"Simplified Chinese - China Mainland",
"简体中文 中国大陆",
),
'zh-TW': (
"繁体中文 中国台湾省",
"Traditional Chinese - Taiwan, China",
"正體中文,中国台灣省",
),
# 'zh-HK': (
# "繁体中文 香港",
# "Traditional Chinese - the Hong Kong Special Administrative Region",
# "繁體中文,香港特別行政區",
# ),
# 'zh-MO': (
# "繁体中文 澳门",
# "Traditional Chinese - the Macao Special Administrative Region",
# "繁體中文,澳門特別行政區",
# ),
'en-GB': (
"英语 英国",
"British English - the United Kingdom",
"British English - the United Kingdom",
),
'zh-ME' : (
"喵喵文 中国大陆",
"Meow Catsese - China Mainland"
"喵喵喵~ 祖国喵~"
)
}
# 对于旧版本音·创的语言支持
# 重构之后将停止使用
try:
from languages.zhCN import READABLETEXT
except:
pass
from msctLib.log import log
def __loadLanguage(languageFilename: str):
with open(languageFilename, 'r', encoding='utf-8') as languageFile:
_text = {}
for line in languageFile:
if line.startswith('#'):
continue
line = line.split(' ', 1)
_text[line[0]] = line[1].replace('\n', '')
langkeys = _text.keys()
with open(languageFilename.replace(languageFilename[-10:-5], 'zh-CN'), 'r', encoding='utf-8') as defaultLangFile:
for line in defaultLangFile:
if line.startswith('#'):
continue
line = line.split(' ', 1)
if not line[0] in langkeys:
_text[line[0]] = line[1].replace('\n', '')
from msctLib.log import log
log(f'丢失对于 {line[0]} 的本地化文本', 'WARRING')
langkeys = _text.keys()
return _text
if not DEFAULTLANGUAGE == 'zh-CN':
if DEFAULTLANGUAGE in LANGUAGELIST.keys():
_TEXT = __loadLanguage('./languages/' + DEFAULTLANGUAGE + '.lang')
else:
raise KeyError(f'无法打开默认语言{DEFAULTLANGUAGE}')
def wordTranslate(singleWord: str, debug: bool = False):
import requests
try:
return \
requests.post('https://fanyi.baidu.com/sug', data={'kw': f'{singleWord}'}).json()['data'][0]['v'].split(
'; ')[0]
except:
log(f"无法翻译文本{singleWord}", level='WARRING', isPrinted=debug)
return None
def _(text: str, debug: bool = False):
try:
return _TEXT[text]
except:
if debug:
raise KeyError(f'无法找到翻译文本{text}')
else:
log(f'无法找到本地化文本{text}','ERROR')
return ''
if __name__ == '__main__':
# 启动语言编辑器
import tkinter as tk
from tkinter.filedialog import askopenfilename as askfilen
LANGNAME = _('LANGLOCALNAME')
def _changeDefaultLang():
global _TEXT
global DEFAULTLANGUAGE
fileName = askfilen(title='选择所翻译的语言文件', initialdir=r'./',
filetypes=[('音·创语言文件', '.lang'), ('所有文件', '*')],
defaultextension='.lang',
initialfile='.lang')
_TEXT = __loadLanguage(fileName)
DEFAULTLANGUAGE = _('LANGKEY')
LANGNAME = _('LANGLOCALNAME')
orignText = ''
transText = ''
for i, j in _TEXT.items():
orignText += i + '\n'
transText += j + '\n'
Origntextbar.insert('end', orignText)
Translatetextbar.insert('end', transText)
global setlangbutton
setlangbutton['text'] = f'对标语言{LANGNAME}'
def _autoSave(event=None):
with open('autosave.tmp.txt', 'w', encoding='utf-8') as f:
f.write(Translatetextbar.get(1.0, 'end'))
print(str(event))
root = tk.Tk()
root.geometry('600x500')
root.bind("<Motion>", _autoSave)
nowText = ''
Orignrame = tk.Frame(root, bd=2)
Translaterame = tk.Frame(root, bd=2)
Orignscrollbar = tk.Scrollbar(Orignrame)
Origntextbar = tk.Text(Orignrame, width=35, height=40)
Translatetextbar = tk.Text(Translaterame, width=40, height=37, undo=True)
Translatescrollbar = tk.Scrollbar(Translaterame)
def ctrlZ():
Translatetextbar.edit_undo()
Translatetextbar.bind("<Control-z>", ctrlZ)
def ctrlY():
Translatetextbar.edit_redo()
Translatetextbar.bind("<Control-y>", ctrlY)
tk.Button(Translaterame, text='保存', command=_autoSave).pack(side='bottom', fill='x')
tk.Label(Orignrame, text='中文原文').pack(side='top')
Origntextbar.pack(side='left', fill='y')
Orignscrollbar.pack(side='left', fill='y')
setlangbutton = tk.Button(Translaterame, text=f'对标语言{LANGNAME}', command=_changeDefaultLang)
setlangbutton.pack(side='top')
Translatescrollbar.pack(side='right', fill='y')
Translatetextbar.pack(side='right', fill='y')
Orignscrollbar.config(command=Origntextbar.yview)
Origntextbar.config(yscrollcommand=Orignscrollbar.set)
Translatescrollbar.config(command=Translatetextbar.yview)
Translatetextbar.config(yscrollcommand=Translatescrollbar.set)
Orignrame.pack(side='left')
Translaterame.pack(side='right')
tk.mainloop()

View File

@@ -1,16 +0,0 @@
# 音·创 本地化语言文件
# 使用 空格 把键与对应文本隔开
# 使用 井字符 在每一行的开头编写注释
# 注意!井字符请开头放,切勿含有空格
# 也切勿在正文结尾放!
LANGKEY zh-CN
LANGCHINESENAME 简体中文 中国大陆
LANGENGLIFHNAME Simplified Chinese, Chinese Mainland
LANGLOCALNAME 简体中文 中国大陆
MSCT 音·创
F音创 音·创 Musicreater
关于 音·创 - 关于
凌云pairs 凌天之云创新我的世界开发团队\n×\n凌天之云创新计算机应用软件开发团队
开发者 - 开发人员 -
译者 - 翻译人员 -
确定 确定

View File

@@ -1,17 +0,0 @@
# 音创创喵的 本地化语言文件
# 使用 空格 把键与对应文本隔开
# 使用 井字符 在每一行的开头编写注释
# 注意!井字符请开头放,切勿含有空格
# 也切勿在正文结尾放!
LANGKEY zh-ME
LANGCHINESENAME 喵喵文 中国大陆
LANGENGLIFHNAME Meow Catsese, China Mainland
LANGLOCALNAME 喵喵喵~ 祖国喵~
TRANSLATERS 金羿,Email EillesWan@outlook.com,QQ 2647547478
MSCT 音创创喵~
F音创 音·创 Musicreater
关于 音创创喵的主人们
凌云pairs 凌天之云创新我的世界开发团队\n×\n凌天之云创新计算机应用软件开发团队
开发者 ~ 主人们 ~
译者 ~ 爸爸妈妈们 ~
确定 好哒~

View File

@@ -1,185 +0,0 @@
# -*- coding:utf-8 -*-
# 由金羿翻译工具生成字符串列表
# 请在所需翻译文件前from 此文件 import READABLETEXT
READABLETEXT = {
'Translator': (("金羿 Eilles 原稿", True),),
# 此处是语言翻译者列表,其中每个元组第一项为显示文本,第二项为此文本是否为开发者名字
0: "错误❌",
1: "提示❗",
2: "清除log此句不载入日志",
3: "无法清除日志及临时文件",
4: "已存储",
5: "新建 音·创 项目",
6: "请选择旧类型的项目",
7: "请选择 音·创 项目",
8: "无法打开文件:{},请查看您是否输入正确",
9: "音·创 - 关于",
10: "音·创 Musicreater",
11: "当前版本:{}",
12: """凌云我的世界开发团队\n×\n凌云计算机应用软件开发团队""",
13: "确定",
14: "请输入音符",
15: (("- 开发者 -", False),
("金羿 Eilles", True), ("EillesWan@outlook.com", False), ("QQ 2647547478", False),
("bgArray “诸葛亮与八卦阵”", True), ("QQ 474037765", False),
),
# 此处是开发者列表,其中每个元组第一项为显示文本,第二项为此文本是否为开发者名字
16: "- 翻译者 -",
# 17:"",
18: "讨论群: 861684859",
19: "音·创 - 帮助",
20: "请选择钢琴声音的音乐文件",
21: "请选择 MIDI 文件",
22: "请选择 音符文本 文件",
23: "获取音符信息",
24: "音符数据写入{}",
25: "请选择文件生成的位置",
26: "请选择文件夹生成的位置",
27: "请选择.mcpack文件生成的位置",
28: "坐标信息输入",
29: "请选择世界文件夹生成的位置",
30: "请选择函数包生成的位置",
31: "请选择 .mcfunction 文件",
32: "请选择需要生成的.bdx文件",
33: "完成✔",
34: "输入播放速度",
35: "创建中",
36: "请选择世界文件夹所在的位置",
37: "请确认",
38: "生成.RyStruct文件",
39: "失败❌",
40: "邮件反馈信息输入",
41: "音·创 - {}",
42: "执行实体名:{}",
43: "使用计分板:{}",
44: "所用的乐器:{}",
45: "当前音轨名:{}",
46: "包名:{}",
47: "音乐标题:{}",
48: "是否重复:{}",
49: "玩家选择器:{}",
50: "修改主设置",
51: "修改节设置",
52: "游戏内置乐器如下:请输入英文\n",
53: "打开音·创项目...",
54: "打开旧项目...",
55: "保存项目",
56: "另存为...",
57: "退出",
58: "文件",
59: "从钢琴MP3导入音轨",
60: "从midi导入音轨",
61: "从文本文件导入音轨",
62: "输入音符至音轨",
63: "编辑",
64: "生成文件至...",
65: "生成函数包至...",
66: "生成附加包文件至...",
67: "函数(包)",
68: "将音乐以方块存储生成地图",
69: "将音乐以方块存储载入地图…",
70: "将音乐以指令存储生成地图",
71: "将音乐以指令存储载入地图…",
72: "将音乐以音符盒存储生成地图",
73: "将音乐以音符盒存储载入地图…",
74: "世界",
75: "生成符合当前音乐的函数播放器…",
76: "将选中音轨以指令存储生成.bdx文件…",
77: "由地图导出至.bdx文件…",
78: "由地图导出至.RyStruct文件…",
79: "将函数载入世界…",
80: "将大函数分割并建立执行链…",
81: "辅助功能",
82: "展示生成结果",
83: "建立位于localhost:8080上的websocket服务器播放选中音轨",
84: "实验性功能",
85: "清除日志文件",
86: "清除早期版本的存储文件",
87: "帮助",
88: "关于",
89: "发送错误日志反馈",
90: "帮助与疑问",
91: "音乐总设置(项目设置)",
# =============================================================此处有新增
92: "将音乐导出为BDX",
93: "请输入指令链生成最高相对高度(≥5)",
94: "您输入的数据有误❌相对高度请输入一个不小于4的值请重新输入。",
95: "结构操作",
96: "重置项目设置",
97: "当前音轨设置(段落设置)",
# 98:"",
# 99:"",
# 100:"",
# 101:"",
102: "删除选中音轨",
# 103:"",
# 104:"",
105: "找不到或无法读取文件😢:{}",
106: "您当前的项目已修改但未存储,是否先保存当前项目?",
107: "项目已经存储至:{}",
108: ("音·创0.0.X工程文件", "音·创0.1+工程文件", "音·创0.1+TEST工程文件"),
109: "任意类型",
110: "函数音创工程文件",
111: "MMFM0.0.6版本工程文件",
112: "全部类型",
113: "钢琴声音的音频文件",
114: "Midi文件",
115: "文本文件",
116: "请输入坐标:",
117: "您输入的格式有误❌,请重新输入。",
118: "我的世界指令函数文件",
119: "请输入执行链生成坐标:",
# 120: "",
121: "您的函数文件不大于一万条指令,无需进行分割操作。",
122: "请输入执行链生成相对坐标:",
123: "FastBuilder结构文件",
124: "转换结束!\n{}",
125: "一秒,音乐走几拍?",
126: "按下确认后在游戏中使用connect指令连接localhost:8080即可播放",
127: "请输入区域选择的开始坐标:",
128: "请输入区域选择的结束坐标:",
129: "所选区块导出时是否需要保留空气方块?",
130: "音·创结构文件",
131: "文件已生成\n{}",
132: "文件无法生成\n{}\n{}",
133: "本功能尚未开发。",
134: "您的称呼",
135: "您的联系方式",
136: "您对问题的描述",
137: "在程序结束后将清除日志及临时文件信息。",
138: "在程序结束后将不会清除日志及临时文件信息。",
139: "修改包名",
140: "修改音乐标题",
141: "修改玩家选择器\n注意!要加上中括号“[]”",
142: "修改本音轨的执行实体名",
143: "修改本音轨所用的积分板",
144: "修改本音轨所用乐器",
145: "您输入的乐器并非游戏内置乐器,是否继续用您输入的字符作为乐器?",
146: "修改本音轨生成的文件名",
# -----2022.1.25更新
147: "生成乐器文件至...",
148: "从midi导入音轨且用新方法解析",
# 149: "打开 新: 音·创项目...",
# 150: "保存为新项目",
# 151: "另存为新项...",
152: "(开发调试)关闭本次日志记录",
153: "生成乐器函数包至...",
154: "生成乐器函数附加包文件至...",
155: "生成乐器函数附加包文件,并将神羽资源包以散包形式放置至...",
156: "[神羽资源包位置选择]:选择文件夹...",
157: "没有路径文件(.rpposi文件)请仔细阅读Readme或先试用帮助与疑问->[神羽资源包位置选择]:选择文件夹... 方法添加路径文件吧!",
158: "有路径文件(.rpposi文件)但路径指示错误请仔细阅读Readme或先用帮助与疑问->[神羽资源包位置选择]:选择文件夹... 更改路径!",
159: "更改路径文件(.rpposi文件)成功!!",
160: "从midi导入音轨且用类方法解析",
# 161: "打开 类方法: 音·创项目...",
# 162: "保存为类方法项目",
# 163: "另存为类方法项...",
164: "生成新文件至...",
165: "生成新函数包至...",
166: "生成新函数附加包文件至...",
167: "这个midi文件读取不了mido解析报错"
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

Binary file not shown.

View File

@@ -1,50 +0,0 @@
# -*- coding: UTF-8 -*-
"""音·创的核心内置组件功能集合"""
class version:
libraries = (
'mido', 'amulet', 'amulet-core', 'amulet-nbt', 'piano_transcription_inference', 'pypinyin',
'pyinstaller', 'py7zr','websockets', 'torch', 'requests'
)
"""当前所需库"""
version = ('0.2.0', 'Delta',)
"""当前版本"""
def __init__(self) -> None:
self.libraries = version.libraries
"""当前所需库"""
self.version = version.version
"""当前版本"""
def installLibraries(self,index:str = 'https://pypi.tuna.tsinghua.edu.cn/simple'):
"""安装全部开发用库"""
from sys import platform
import os
if platform == 'win32':
import shutil
try:
shutil.rmtree(os.getenv('APPDATA') + '\\Musicreater\\')
except FileNotFoundError:
pass
for i in self.libraries:
print("安装库:" + i)
os.system(f"python -m pip install {i} -i {index}")
elif platform == 'linux':
os.system("sudo apt-get install python3-pip")
os.system("sudo apt-get install python3-tk")
os.system("sudo apt-get install python3-tkinter")
for i in self.libraries:
print("安装库:" + i)
os.system(f"sudo python3 -m pip install {i} -i {index}")
def __call__(self):
'''直接安装库,顺便返回一下当前版本'''
self.installLibraries()
return self.version

View File

@@ -1,151 +0,0 @@
# -*- coding:utf-8 -*-
import pickle
import json
from typing import Any, Iterable
class pickleIO:
def __init__(self,fileName:str,data: Any = None) -> None:
'''简单的pickle操作功能'''
self.file = fileName
if data:
self._data = data
else:
with open (self.file, 'rb') as f:
self._data = pickle.load(f)
def __call__(self, *args: Any, **kwds: Any) -> Any:
return self.data
def write(self):
'''将数据写入pickle'''
with open (self.file, 'wb') as f:
pickle.dump(self._data, f)
def load(self) -> Any:
'''从文件读取数据'''
with open (self.file, 'rb') as f:
self._data = pickle.load(f)
return self.data
@property
def data(self):
'''返回数据值'''
if self._data is None:
raise ValueError('无可用值载入或值为None')
else:
return self._data
class jsonIO:
def __init__(self,fileName:str,data: Any = None) -> None:
'''简单的json操作功能'''
self.file = fileName
if data:
self._data = data
else:
with open (self.file, 'r', encoding='utf-8') as f:
self._data = json.load(f)
def __call__(self, *args: Any, **kwds: Any) -> Any:
return self.data
def write(self):
'''将数据写入json'''
with open (self.file, 'w', encoding='utf-8') as f:
json.dump(self._data, f)
def load(self) -> Any:
'''从文件读取数据'''
with open (self.file, 'r', encoding='utf-8') as f:
self._data = json.load(f)
return self.data
@property
def data(self):
'''返回数据值'''
return self._data
class uniteIO:
def __init__(self,fileName:str,fileType = None,data: Any = None) -> None:
'''简单的文件数据IO操作功能'''
self.filename = fileName
if not fileType is None:
self._type = fileType
else:
try:
with open (self.filename, 'r', encoding='utf-8') as f:
self._type = json
except:
with open (self.file, 'rb') as f:
self._type = pickle
if not data is None:
self._data = data
else:
self._data = self.load()
def __call__(self, *args: Any, **kwds: Any) -> Any:
return self.data
def write(self):
'''将数据写入文件'''
if self._type == json:
self._wfile = open(self.filename, 'w', encoding='utf-8')
elif self._type == pickle:
self._wfile = open(self.file, 'wb')
self._type.dump(self._data, self._wfile)
def load(self) -> Any:
'''从文件读取数据'''
if self._type == json:
self._rfile = open(self.filename, 'r', encoding='utf-8')
elif self._type == pickle:
self._rfile = open(self.file, 'rb')
self._data = self._type.load(self._rfile)
return self.data
@property
def data(self):
'''返回数据值'''
return self._data
if __name__ == '__main__':
from sys import argv
if argv[1]:
input(uniteIO(argv[1]).data)

Some files were not shown because too many files have changed in this diff Show More