mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2026-01-08 12:52:11 +00:00
Compare commits
1 Commits
nbs
...
beewarewin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acf4c6907e |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,3 +0,0 @@
|
||||
*.yaml linguist-language=Python
|
||||
*.xml linguist-language=Python
|
||||
*.md linguist-language=Python
|
||||
187
.gitignore
vendored
187
.gitignore
vendored
@@ -1,29 +1,38 @@
|
||||
# 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
|
||||
|
||||
# Byte-compiled / optimized
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# OSX useful to ignore
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
@@ -35,129 +44,23 @@ 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
|
||||
# IntelliJ Idea family of suites
|
||||
.idea
|
||||
*.iml
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
## mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# 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
|
||||
# Briefcase build directories
|
||||
iOS/
|
||||
macOS/
|
||||
windows/
|
||||
android/
|
||||
linux/
|
||||
django/
|
||||
|
||||
@@ -1,219 +1,201 @@
|
||||
**注意,以下条款或版权声明应当且必须是高于此项目中任何其他声明的**
|
||||
|
||||
1. 音·创的全部开发者享有其完整版权,其开发者可以在任一时刻终止以后音·创源代码开放,若经由其开发者授予特殊权利,则授权对象可以将源代码进行特定的被特殊授权的操作
|
||||
2. 音·创或(及)其代码允许在 Apache2.0 协议的条款与说明下进行非商业使用
|
||||
3. 除部分代码特殊声明外,音·创允许对其或(及)其代码进行商业化使用,但是需要经过音·创主要开发者(诸葛亮与八卦阵、金羿)的一致授权,同时,授权对象在商业化授权的使用过程中必须依照 Apache2.0 协议的条款与说明
|
||||
4. 若存在对于音·创包含的部分代码的特殊开源声明,则此部分代码依照其特定的开源方式授权,但若此部分代码经由此部分代码的主要开发者一致特殊授权后商用,则授权对象在商用时依照此部分的开发者所准许的方式(或条款)进行商用,或默认依照 Apache2.0 协议进行商业化使用
|
||||
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 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 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
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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,24 +0,0 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
# 睿穆组织 开发交流群 861684859
|
||||
# Email TriM-Organization@hotmail.com
|
||||
# 版权所有 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray") & 鸣凤鸽子("MingFengPigeon")
|
||||
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
|
||||
|
||||
from .main import *
|
||||
|
||||
__version__ = "0.5.1"
|
||||
__all__ = []
|
||||
__author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray"), ("鸣凤鸽子", "MingFengPigeon"))
|
||||
@@ -1,102 +0,0 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
|
||||
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 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)
|
||||
@@ -1,219 +0,0 @@
|
||||
pitched_instrument_list = {
|
||||
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), # 打击乐器无音域
|
||||
}
|
||||
|
||||
percussion_instrument_list = {
|
||||
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),
|
||||
}
|
||||
|
||||
instrument_to_blocks_list = {
|
||||
"note.bass": ("planks",),
|
||||
"note.snare": ("sand",),
|
||||
"note.hat": ("glass",),
|
||||
"note.bd": ("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": ("glass",),
|
||||
}
|
||||
|
||||
nbs_instrument_to_name = {
|
||||
0: "Piano", # (air)
|
||||
1: "Double Bass", # (Wood)
|
||||
2: "Bass Drum", # (Stone)
|
||||
3: "Snare Drum", # (Sand)
|
||||
4: "Click", # (Glass)
|
||||
5: "Guitar", # (Wool)
|
||||
6: "Flute", # (Clay)
|
||||
7: "Bell", # (Block of Gold)
|
||||
8: "Chime", # (Packed Ice)
|
||||
9: "Xylophone", # (Bone Block)
|
||||
10: "Iron Xylophone", # (Iron Block)
|
||||
11: "Cow Bell", # (Soul Sand)
|
||||
12: "Didgeridoo", # (Pumpkin)
|
||||
13: "Bit", # (Block of Emerald)
|
||||
14: "Banjo", # (Hay)
|
||||
15: "Pling", # (Glowstone)
|
||||
}
|
||||
@@ -1,305 +0,0 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================
|
||||
|
||||
|
||||
|
||||
|
||||
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 Union
|
||||
from .utils import x,y,z,bottem_side_length_of_smallest_square_bottom_box,form_note_block_in_NBT_struct,form_repeater_in_NBT_struct
|
||||
|
||||
# 不要用 没写完
|
||||
def delay_to_note_blocks(
|
||||
baseblock: str = "stone",
|
||||
position_forward: Union(x, y, z) = z,
|
||||
max_height: int = 64,
|
||||
):
|
||||
"""传入音符,生成以音符盒存储的红石音乐
|
||||
:param:
|
||||
baseblock: 中继器的下垫方块
|
||||
position_forward: 结构延长方向
|
||||
:return 是否生成成功
|
||||
"""
|
||||
|
||||
from TrimMCStruct import Structure, Block
|
||||
|
||||
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
|
||||
len(commands), max_height
|
||||
)
|
||||
|
||||
struct = Structure(
|
||||
(_sideLength, max_height, _sideLength), # 声明结构大小
|
||||
)
|
||||
|
||||
log = print
|
||||
|
||||
startpos = [0,0,0]
|
||||
|
||||
|
||||
# 1拍 x 2.5 rt
|
||||
def placeNoteBlock():
|
||||
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]
|
||||
|
||||
# e = True
|
||||
try:
|
||||
placeNoteBlock()
|
||||
# e = False
|
||||
except: # ValueError
|
||||
log("无法放置方块了,可能是因为区块未加载叭")
|
||||
|
||||
|
||||
2145
Musicreater/main.py
2145
Musicreater/main.py
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,459 +0,0 @@
|
||||
import math
|
||||
import os
|
||||
|
||||
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+]是用来增加指定数目的"""
|
||||
|
||||
x = "x"
|
||||
y = "y"
|
||||
z = "z"
|
||||
|
||||
|
||||
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 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
|
||||
"""
|
||||
import zipfile
|
||||
|
||||
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 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 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)))
|
||||
|
||||
|
||||
def commands_to_BDX_bytes(
|
||||
commands: list,
|
||||
max_height: int = 64,
|
||||
):
|
||||
"""
|
||||
:param commands: 指令列表(指令, 延迟)
|
||||
:param max_height: 生成结构最大高度
|
||||
:return 成功与否,成功返回(True,未经过压缩的源,结构占用大小),失败返回(False,str失败原因)
|
||||
"""
|
||||
|
||||
_sideLength = bottem_side_length_of_smallest_square_bottom_box(
|
||||
len(commands), max_height
|
||||
)
|
||||
_bytes = b""
|
||||
|
||||
y_forward = True
|
||||
z_forward = True
|
||||
|
||||
now_y = 0
|
||||
now_z = 0
|
||||
now_x = 0
|
||||
|
||||
for cmd, delay in commands:
|
||||
impluse = 2
|
||||
condition = False
|
||||
needRedstone = False
|
||||
tickDelay = delay
|
||||
customName = ""
|
||||
executeOnFirstTick = False
|
||||
trackOutput = True
|
||||
_bytes += form_command_block_in_BDX_bytes(
|
||||
cmd,
|
||||
(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=impluse,
|
||||
condition=condition,
|
||||
needRedstone=needRedstone,
|
||||
tickDelay=tickDelay,
|
||||
customName=customName,
|
||||
executeOnFirstTick=executeOnFirstTick,
|
||||
trackOutput=trackOutput,
|
||||
)
|
||||
|
||||
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],
|
||||
)
|
||||
|
||||
|
||||
def form_note_block_in_NBT_struct(
|
||||
note: int, coordinate: tuple, 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
|
||||
"""
|
||||
|
||||
from TrimMCStruct import Block, TAG_Byte
|
||||
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],
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def form_repeater_in_NBT_struct(
|
||||
delay: int, facing: int
|
||||
):
|
||||
"""生成中继器方块
|
||||
:param facing:
|
||||
:param delay: 1~4
|
||||
:return Block()"""
|
||||
|
||||
from TrimMCStruct import 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
|
||||
"""
|
||||
|
||||
from TrimMCStruct import Block, TAG_Long
|
||||
|
||||
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],
|
||||
}
|
||||
},
|
||||
compability_version=17959425,
|
||||
)
|
||||
|
||||
|
||||
def commands_to_structure(
|
||||
commands: list,
|
||||
max_height: int = 64,
|
||||
):
|
||||
"""
|
||||
:param commands: 指令列表(指令, 延迟)
|
||||
:param max_height: 生成结构最大高度
|
||||
:return 成功与否,成功返回(结构类,结构占用大小),失败返回(False,str失败原因)
|
||||
"""
|
||||
|
||||
from TrimMCStruct import Structure
|
||||
|
||||
_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 cmd, delay in commands:
|
||||
coordinate = (now_x, now_y, now_z)
|
||||
struct.set_block(
|
||||
coordinate,
|
||||
form_command_block_in_NBT_struct(
|
||||
command=cmd,
|
||||
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=delay,
|
||||
customName="",
|
||||
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),
|
||||
)
|
||||
164
README.md
164
README.md
@@ -1,133 +1,49 @@
|
||||
# 音·创 Musicreater
|
||||
|
||||
<h1 align="center">
|
||||
音·创 Musicreater
|
||||
</h1>
|
||||
### 介绍
|
||||
音·创(Musicreater)是由金羿(W-YI)开发的一款《我的世界》基岩版音乐生成辅助软件
|
||||
|
||||
<p align="center">
|
||||
<img width="128" height="128" src="https://gitee.com/TriM-Organization/Musicreater/raw/master/resources/msctIcon.ico">
|
||||
</img>
|
||||
</p>
|
||||
欢迎加群:861684859
|
||||
|
||||
<h3 align="center">一款免费开源的 《我的世界》 MIDI音乐转换库。</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>
|
||||
软件采用Python作为第一语言,目前还没有使用其他语言辅助。使用BeeWare作为图形库兼容安卓。
|
||||
|
||||
尽量全平台支持
|
||||
|
||||
|
||||
### 安装教程
|
||||
|
||||
#### Windows
|
||||
|
||||
即将到来。
|
||||
|
||||
#### Linux
|
||||
|
||||
即将到来。
|
||||
|
||||
#### Android
|
||||
|
||||
即将到来。
|
||||
|
||||
### 使用说明
|
||||
|
||||
1. 直接运行就好
|
||||
2. 有不懂的问题来群里问
|
||||
3. 请理解英文表述
|
||||
|
||||
### 致谢
|
||||
|
||||
1. 感谢由 [Fuckcraft](https://github.com/fuckcraft) “鸣凤鸽子”等 带来的我的世界websocket服务器功能
|
||||
2. 感谢 昀梦<QQ1515399885> 找出指令生成错误bug并指正
|
||||
3. 感谢由 Charlie_Ping “查理平” 带来的bdx转换功能
|
||||
4. 感谢由 CMA_2401PT 提供的 BDXWorkShop作为.bdx结构的操作指导
|
||||
5. 感谢广大群友为此程序提供的测试等支持
|
||||
6. 若您为我找出了错误但您的名字没有显示在此列表中,请联系我!
|
||||
|
||||
|
||||
### 作者<金羿>联系方式
|
||||
|
||||
[![][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)
|
||||
|
||||
[](https://gitee.com/TriM-Organization/Musicreater/stargazers)
|
||||
[](https://gitee.com/TriM-Organization/Musicreater/members)
|
||||
[](https://github.com/TriM-Organization/Musicreater/stargazers)
|
||||
[](https://github.com/TriM-Organization/Musicreater/forks)
|
||||
|
||||
|
||||
简体中文🇨🇳 | [English🇬🇧](README_EN.md)
|
||||
|
||||
|
||||
## 介绍🚀
|
||||
|
||||
音·创 是一个免费开源的针对 **《我的世界》** 的MIDI音乐转换库
|
||||
|
||||
欢迎加群:[861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
|
||||
|
||||
## 下载安装
|
||||
|
||||
- 使用pypi
|
||||
```bash
|
||||
pip install Musicreater
|
||||
```
|
||||
|
||||
- 如果出现错误,可以尝试:
|
||||
```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
|
||||
```
|
||||
|
||||
以上命令种 `python`、`pip` 请依照各个环境不同灵活更换,可能为`python3`或`pip3`之类。
|
||||
|
||||
## 文档📄
|
||||
|
||||
[生成文件的使用](./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)
|
||||
|
||||
## 作者✒
|
||||
|
||||
金羿 Eilles:我的世界基岩版指令师,个人开发者,B站不知名UP主,江西在校高中生。
|
||||
|
||||
诸葛亮与八卦阵 bgArray:我的世界基岩版玩家,喜欢编程和音乐,深圳初二学生。
|
||||
|
||||
## 致谢🙏
|
||||
本致谢列表排名无顺序。
|
||||
|
||||
- 感谢 **昀梦**\<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。
|
||||
|
||||
> 感谢广大群友为此程序提供的测试等支持
|
||||
>
|
||||
> 若您对我们有所贡献但您的名字没有显示在此列表中,请联系我们!
|
||||
|
||||
## 联系📞
|
||||
|
||||
若遇到库中的问题,欢迎在[此](https://gitee.com/TriM-Organization/Musicreater/issues/new)提出你的issue。
|
||||
|
||||
如果需要与开发组进行交流,欢迎加入我们的[开发闲聊Q群](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)。
|
||||
|
||||
--------------------------------------------
|
||||
|
||||
此项目并非一个官方 《我的世界》(*Minecraft*)项目
|
||||
|
||||
此项目不隶属或关联于 Mojang Studios 或 微软
|
||||
|
||||
此项目亦不与 网易 相关
|
||||
|
||||
“Minecraft”是 Mojang Synergies AB 的商标,此项目中所有对于“我的世界”、“Minecraft”等相关称呼均为引用性使用
|
||||
|
||||
* 上文提及的 网易 公司,指代的是在中国大陆运营《我的世界:中国版》的上海网之易网络科技发展有限公司
|
||||
|
||||
NOT AN OFFICIAL MINECRAFT PRODUCT.
|
||||
|
||||
NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[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
|
||||
1. QQ 2647547478
|
||||
2. 电邮 EillesWan2006@163.com W-YI_DoctorYI@outlook.com
|
||||
3. 微信 WYI_DoctorYI
|
||||
12
README.rst
Normal file
12
README.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
Musicreater
|
||||
===========
|
||||
|
||||
**This cross-platform app was generated by** `Briefcase`_ **- part of**
|
||||
`The BeeWare Project`_. **If you want to see more tools like Briefcase, please
|
||||
consider** `becoming a financial member of BeeWare`_.
|
||||
|
||||
音·创(Musicreater)是由金羿(W-YI)开发的一款《我的世界》基岩版音乐生成辅助软件
|
||||
|
||||
.. _`Briefcase`: https://github.com/beeware/briefcase
|
||||
.. _`The BeeWare Project`: https://beeware.org/
|
||||
.. _`becoming a financial member of BeeWare`: https://beeware.org/contributing/membership
|
||||
86
README_EN.md
86
README_EN.md
@@ -1,86 +0,0 @@
|
||||
<h1 align="center">音·创 Musicreater</h1>
|
||||
|
||||
<p align="center">
|
||||
<img width="128" height="128" src="https://s1.ax1x.com/2022/05/06/Ouhghj.md.png" >
|
||||
</p>
|
||||
|
||||
<h3 align="center">a free open-source library of converting midi files into _Minecraft_ formats.</h3>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://forthebadge.com/images/badges/built-with-love.svg">
|
||||
<p>
|
||||
|
||||
[![][Bilibili: Eilles]](https://space.bilibili.com/397369002/)
|
||||
[![][Bilibili: bgArray]](https://space.bilibili.com/604072474)
|
||||
[![CodeStyle: black]](https://github.com/psf/black)
|
||||
![][python]
|
||||
[![][license]](LICENSE)
|
||||
[![][release]](../../releases)
|
||||
|
||||
[简体中文🇨🇳](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 midi file into formats that could be read in *Minecraft*.
|
||||
|
||||
Welcome to join our QQ group: [861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr)
|
||||
|
||||
## 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 bdx convert function for reference, and the 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
|
||||
- 感谢 *[神羽](https://gitee.com/snowykami) “[SnowyKami](https://github.com/snowyfirefly)”* for supporting and promoting our project
|
||||
|
||||
> Thanks for a lot of groupmates's 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://gitee.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.
|
||||
|
||||
此项目并非一个官方 《我的世界》(*Minecraft*)项目
|
||||
|
||||
此项目不隶属或关联于 Mojang Studios 或 微软
|
||||
|
||||
|
||||
|
||||
|
||||
[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.6-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
|
||||
52
README_en.md
Normal file
52
README_en.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Musicreater
|
||||
|
||||
### 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
|
||||
|
||||
### Framework
|
||||
|
||||
Use *Python* to develop, use *BeeWare* as a Windows Library.
|
||||
|
||||
We are trying to support every platform.
|
||||
|
||||
|
||||
### Tutorials
|
||||
|
||||
#### Windows
|
||||
|
||||
Please wait for a while...
|
||||
Comming soon
|
||||
|
||||
#### Linux
|
||||
|
||||
Please wait for a while...
|
||||
Comming soon
|
||||
|
||||
#### Android
|
||||
|
||||
Please wait for a while...
|
||||
Comming soon
|
||||
|
||||
### 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.
|
||||
|
||||
### Thanks
|
||||
|
||||
1. Thank [Fuckcraft](https://github.com/fuckcraft) “鸣凤鸽子”and so on for the function of Creating the Websocket Server for Minecraft: Bedrock Edition.
|
||||
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. Thanks for a lot of groupmates who support me and help me to test the program.
|
||||
6. If u 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
|
||||
1
Run in devmode.bat
Normal file
1
Run in devmode.bat
Normal file
@@ -0,0 +1 @@
|
||||
briefcase dev
|
||||
60
Run the Ver Build under Tkinter.py
Normal file
60
Run the Ver Build under Tkinter.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os,shutil
|
||||
from sys import platform
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
print("更新执行位置...")
|
||||
if platform == 'win32':
|
||||
try:
|
||||
os.chdir(__file__[:len(__file__)-__file__[len(__file__)::-1].index('\\')]+'src\\')
|
||||
print("更新执行位置,当前文件位置"+__file__)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
os.chdir(__file__[:len(__file__)-__file__[len(__file__)::-1].index('/')]+'src/')
|
||||
except:
|
||||
pass
|
||||
print("其他平台:"+platform+"更新执行位置,当前文件位置"+__file__)
|
||||
print('完成!')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
import toga,amulet
|
||||
except:
|
||||
print("You'd better install the libraries of this app\nNow, we're helping you with this.")
|
||||
from src.musicreater.msctspt.bugReporter import version
|
||||
version.installLibraries(version)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if platform == 'win32':
|
||||
os.system("python ./Musicreater.py")
|
||||
elif platform == 'linux':
|
||||
os.system("python3 ./Musicreater.py")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
if os.path.exists("./log/"):
|
||||
shutil.rmtree("./log/")
|
||||
if os.path.exists("./logs/"):
|
||||
shutil.rmtree("./logs/")
|
||||
if os.path.exists("./cache/"):
|
||||
shutil.rmtree("./cache/")
|
||||
except:
|
||||
print("无法清除日志及临时文件")
|
||||
@@ -1,22 +0,0 @@
|
||||
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()
|
||||
@@ -1,204 +0,0 @@
|
||||
<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#L120),使用此库进行MIDI转换非常简单。
|
||||
|
||||
```python
|
||||
import Musicreater # 导入转换库
|
||||
|
||||
old_execute_format = False # 指定是否使用旧的execute指令语法(即1.18及以前的《我的世界:基岩版》语法)
|
||||
|
||||
# 首先新建转换对象。
|
||||
conversion = Musicreater.midiConvert(enable_old_exe_format = old_execute_format)
|
||||
# 值得注意的是,一个转换对象可以转换多个文件。
|
||||
# 也就是在实例化的时候不进行对文件的绑定。
|
||||
# 如果有调试需要,可以在实例化时传入参数 debug = True
|
||||
# 如:conversion = Musicreater.midiConvert(debug=True)
|
||||
|
||||
# 设置输入输出地址,并指定execute指令语法
|
||||
# 地址都为字符串类型,不能传入文件流
|
||||
midi_path = "./where/you/place/.midi/files.mid"
|
||||
output_folder = "./where/you/want2/convert/into/"
|
||||
|
||||
# 设定基本转换参数
|
||||
conversion.convert(midi_path,output_folder)
|
||||
|
||||
# 进行转换并接受输出,具体的参数均在代码之文档中有相关说明
|
||||
method_id = 3 # 指定使用的转换算法
|
||||
|
||||
# 使用计分板播放器,转换为附加包文件
|
||||
convertion_result = conversion.to_mcpack(method_id,*prompts)
|
||||
|
||||
# 使用延迟播放器,转换为附加包文件
|
||||
# 注意,在执行这个功能之前,你需要使用指令
|
||||
# pip install TrimMCStruct
|
||||
# 安装最新版的TrimMCStruct库
|
||||
convertion_result = conversion.to_mcpack_with_delay(method_id,*prompts)
|
||||
|
||||
# 使用计分板播放器,转换为BDX结构文件
|
||||
convertion_result = conversion.to_BDX_file(method_id,*prompts)
|
||||
|
||||
# 使用延迟播放器,转换为BDX结构文件
|
||||
convertion_result = conversion.to_BDX_file_with_delay(method_id,*prompts)
|
||||
|
||||
# 转换结果是一个元组。
|
||||
# 若其转换成功,则前三位必为
|
||||
# True, 指令数量, 最大延迟
|
||||
# 其中,最大延迟可以理解为计分板的最大值
|
||||
# 如果转换失败,暂时还没有定返回值的规则
|
||||
# 但是有一点是肯定的,数据结构必定是元组
|
||||
print(convertion_result)
|
||||
```
|
||||
|
||||
|
||||
# 生成文件结构
|
||||
|
||||
## 名词解释
|
||||
|
||||
|名词|解释|备注|
|
||||
|--------|-----------|----------|
|
||||
|指令区|一个用于放置指令系统的区域,通常是常加载区。|常见于服务器指令系统、好友联机房间中|
|
||||
|指令链(链)|与链式指令方块不同,一个指令链通常指代的是一串由某种非链式指令方块作为开头,后面连着一串链式指令方块的结构。|通常的链都应用于需要“单次激活而多指令”的简单功能|
|
||||
|起始块|链最初的那个非链式指令方块。|此方块为脉冲方块或重复方块皆可|
|
||||
|指令系统(系统)|指令系统通常指的是,由一个或多个指令链以及相关红石机构相互配合、一同组成的,为达到某种特定的功能而构建的整体结构。|通常的系统都应用于需要“综合调配指令”的复杂功能。可由多个实现不同功能的模块构成,不同系统之间可以相互调用各自的模块。|
|
||||
|游戏刻(刻)|游戏的一刻是指《我的世界》的游戏循环运行一次所占用的时间。([详见《我的世界》中文维基](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'))`
|
||||
|
||||
*对了!为了避免生成错误,请尽量避免使用标识符作为定义样式字符串的其他部分*
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<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%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.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. 若想要重置某实体的播放,可以将其播放用的计分板重置
|
||||
|
||||
> 其中 步骤三 和 步骤四 的顺序可以调换。
|
||||
|
||||
## 结构格式
|
||||
|
||||
支持的文件后缀:`.MCSTRUCTURE`、`.BDX`
|
||||
|
||||
1. 将结构导入世界
|
||||
|
||||
- 延迟播放器
|
||||
|
||||
2. 将结构生成的第一个指令方块之模式更改为**脉冲**
|
||||
3. 激活脉冲方块
|
||||
4. 若欲重置播放,可以停止对此链的激活,例如停止区块加载
|
||||
5. 此播放器不支持暂停
|
||||
|
||||
- 计分板播放器
|
||||
|
||||
2. 在所生成的第一个指令方块前,放置一个循环指令方块,其朝向应当对着所生成的第一个方块
|
||||
3. 在循环指令方块中输入使播放对象的播放用计分板加分的指令,延迟为`0`,每次循环增加`1`分
|
||||
4. 激活循环方块
|
||||
5. 若想要暂停播放,可以停止循环指令方块的激活状态
|
||||
6. 若想要重置某实体的播放,可以将其播放用的计分板重置
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
# 暂无
|
||||
149
example.py
149
example.py
@@ -1,149 +0,0 @@
|
||||
# -*- 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
|
||||
|
||||
|
||||
# 获取midi列表
|
||||
midi_path = input(f"请输入MIDI路径:")
|
||||
|
||||
|
||||
# 获取输出地址
|
||||
out_path = input(f"请输入输出路径:")
|
||||
|
||||
conversion = Musicreater.midiConvert()
|
||||
|
||||
|
||||
def isMethodOK(sth: str):
|
||||
if int(sth) in range(1, len(conversion.methods) + 1):
|
||||
return int(sth)
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
|
||||
convert_method = int(input(f"请输入转换算法[1~{len(conversion.methods)}]:"))
|
||||
|
||||
# 选择输出格式
|
||||
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("布尔字符串啊?")
|
||||
|
||||
|
||||
debug = False
|
||||
|
||||
if os.path.exists("./demo_config.json"):
|
||||
import json
|
||||
|
||||
prompts = json.load(open("./demo_config.json", "r", encoding="utf-8"))
|
||||
if prompts[-1] == "debug":
|
||||
debug = True
|
||||
prompts = prompts[:-1]
|
||||
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 (),
|
||||
(
|
||||
f"最大结构高度:",
|
||||
int,
|
||||
)
|
||||
if fileFormat == 1
|
||||
else (),
|
||||
]:
|
||||
if args:
|
||||
prompts.append(args[1](input(args[0])))
|
||||
|
||||
conversion = Musicreater.midiConvert(debug=debug)
|
||||
|
||||
|
||||
print(f"正在处理 {midi_path} :")
|
||||
conversion.convert(midi_path, out_path)
|
||||
if debug:
|
||||
with open("./records.json", "a", encoding="utf-8") as f:
|
||||
json.dump(conversion.toDICT(), f)
|
||||
f.write(5 * "\n")
|
||||
conversion_result = (
|
||||
conversion.to_mcpack(convert_method, *prompts)
|
||||
if fileFormat == 0
|
||||
else (
|
||||
conversion.to_BDX_file(convert_method, *prompts)
|
||||
if playerFormat == 1
|
||||
else conversion.to_BDX_file_with_delay(convert_method, *prompts)
|
||||
)
|
||||
)
|
||||
|
||||
if conversion_result[0]:
|
||||
print(
|
||||
f" 指令总长:{conversion_result[1]},最高延迟:{conversion_result[2]}{f''',结构大小{conversion_result[3]},最末坐标{conversion_result[4]}''' if fileFormat == 1 else ''}"
|
||||
)
|
||||
else:
|
||||
print(f"失败:{conversion_result}")
|
||||
|
||||
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")
|
||||
@@ -1,8 +0,0 @@
|
||||
from Musicreater import midiConvert
|
||||
|
||||
conversion = midiConvert(enable_old_exe_format=False)
|
||||
conversion.convert(input("midi路径:"), input("输出路径:"))
|
||||
|
||||
conversion.to_mcstructure_file_with_delay(
|
||||
3,
|
||||
)
|
||||
47
poem.txt
47
poem.txt
@@ -1,47 +0,0 @@
|
||||
> 是谁把科技的领域布满政治的火药
|
||||
>
|
||||
> 是谁把纯净的蓝天染上暗淡的沉灰
|
||||
>
|
||||
> 中国人民无不热爱自己伟大的祖国
|
||||
>
|
||||
> 我们不会忘记屈辱历史留下的惨痛
|
||||
>
|
||||
> 我们希望世界和平
|
||||
>
|
||||
> 我们希望获得世界的尊重
|
||||
>
|
||||
> 愿世上再也没有战争
|
||||
>
|
||||
> 无论是热还是冷
|
||||
>
|
||||
> 无论是经济还是政治
|
||||
>
|
||||
> 让美妙的和平的优雅的音乐响彻世界
|
||||
>
|
||||
> ——金羿
|
||||
> 2022 5 7
|
||||
|
||||
|
||||
|
||||
> Who has dropped political gunpowder into the technology
|
||||
>
|
||||
> Who has dyed clear blue sky into the dark grey
|
||||
>
|
||||
> All Chinese people love our great homeland
|
||||
>
|
||||
> We *WILL* remember the remain pain of the humiliating history
|
||||
>
|
||||
> We love the whole world but in peace
|
||||
>
|
||||
> We love everyone but under respect
|
||||
>
|
||||
> It is to be hoped that the war ends forever
|
||||
>
|
||||
> Whatever it is cold or hot
|
||||
>
|
||||
> Whatever it is economical or political
|
||||
>
|
||||
> Just let the wonderful music of peace surround the world
|
||||
>
|
||||
> ---- Eilles Wan
|
||||
> 7/5 2022
|
||||
49
pyproject.toml
Normal file
49
pyproject.toml
Normal file
@@ -0,0 +1,49 @@
|
||||
[tool.briefcase]
|
||||
project_name = "Musicreater"
|
||||
bundle = "com.ryoun.musicreater"
|
||||
version = "0.0.1"
|
||||
url = "https://musicreater.ryoun.com/musicreater"
|
||||
license = "Apache Software License"
|
||||
author = 'Eilles Wan'
|
||||
author_email = "W-YI_DoctorYI@outlook.com"
|
||||
|
||||
[tool.briefcase.app.musicreater]
|
||||
formal_name = "Musicreater"
|
||||
description = "Musicreater is an Eilles's app that is used for creating musics in Minecraft: Bedrock Edition"
|
||||
icon = "src/musicreater/resources/musicreater"
|
||||
sources = ['src/musicreater']
|
||||
requires = []
|
||||
|
||||
|
||||
[tool.briefcase.app.musicreater.macOS]
|
||||
requires = [
|
||||
'toga-cocoa>=0.3.0.dev20',
|
||||
]
|
||||
|
||||
[tool.briefcase.app.musicreater.linux]
|
||||
requires = [
|
||||
'toga-gtk>=0.3.0.dev20',
|
||||
]
|
||||
system_requires = [
|
||||
'libgirepository1.0-dev',
|
||||
'libcairo2-dev',
|
||||
'libpango1.0-dev',
|
||||
'libwebkitgtk-3.0-0',
|
||||
'gir1.2-webkit-3.0',
|
||||
]
|
||||
|
||||
[tool.briefcase.app.musicreater.windows]
|
||||
requires = [
|
||||
'toga-winforms>=0.3.0.dev20',
|
||||
]
|
||||
|
||||
# Mobile deployments
|
||||
[tool.briefcase.app.musicreater.iOS]
|
||||
requires = [
|
||||
'toga-iOS>=0.3.0.dev20',
|
||||
]
|
||||
|
||||
[tool.briefcase.app.musicreater.android]
|
||||
requires = [
|
||||
'toga-android>=0.3.0.dev20',
|
||||
]
|
||||
@@ -1,2 +0,0 @@
|
||||
Brotli>=1.0.9
|
||||
mido>=1.2.10
|
||||
@@ -1,21 +0,0 @@
|
||||
# 注意,这里是作者署名文件,文件格式开头为单子启
|
||||
# 紧跟其后,不加空格留下常用名,常用名即常用网名
|
||||
# 而在其后是各个语言下的名字。用 井字符 开头表示
|
||||
# 注释,请注意,注释符号必须在一行之首否则无作用
|
||||
# 每进行一次分段表示一个新的开发者,换行表示一个
|
||||
# 新的语言。请全体开发者就此署名,谢谢!
|
||||
启金羿
|
||||
zh-CN 金羿
|
||||
zh-TW 金羿
|
||||
zh-ME 金羿羿喵
|
||||
zh-HK 金 羿
|
||||
en-GB Eilles Wan
|
||||
en-US EillesWan
|
||||
|
||||
启诸葛亮与八卦阵
|
||||
zh-CN 诸葛亮与八卦阵
|
||||
zh-TW 諸葛亮與八卦陣
|
||||
zh-ME 诸葛八卦喵
|
||||
zh-HK 諸葛亮與八卦陣
|
||||
en-GB Bagua Array
|
||||
en-US bgArray
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 MiB |
40
setup.py
40
setup.py
@@ -1,40 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import setuptools
|
||||
import Musicreater
|
||||
|
||||
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
||||
dependences = fh.read().strip().split("\n")
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
long_description = fh.read().replace(
|
||||
"./docs/", "https://github.com/TriM-Organization/Musicreater/blob/master/docs/"
|
||||
)
|
||||
|
||||
setuptools.setup(
|
||||
name="Musicreater",
|
||||
version=Musicreater.__version__,
|
||||
author="Eilles Wan, bgArray",
|
||||
author_email="TriM-Organization@hotmail.com",
|
||||
description="一款免费开源的 《我的世界》 mid音乐转换库。\n"
|
||||
"A free open-source python library used to convert midi into Minecraft.",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/TriM-Organization/Musicreater",
|
||||
packages=setuptools.find_packages(),
|
||||
classifiers=[
|
||||
"Intended Audience :: Developers",
|
||||
"Natural Language :: Chinese (Simplified)",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
],
|
||||
# 需要安装的依赖
|
||||
install_requires=dependences,
|
||||
)
|
||||
1401
src/Musicreater.py
Normal file
1401
src/Musicreater.py
Normal file
File diff suppressed because it is too large
Load Diff
1
src/musicreater.dist-info/INSTALLER
Normal file
1
src/musicreater.dist-info/INSTALLER
Normal file
@@ -0,0 +1 @@
|
||||
briefcase
|
||||
10
src/musicreater.dist-info/METADATA
Normal file
10
src/musicreater.dist-info/METADATA
Normal file
@@ -0,0 +1,10 @@
|
||||
Metadata-Version: 2.1
|
||||
Briefcase-Version: 0.3.5
|
||||
Name: musicreater
|
||||
Formal-Name: Musicreater
|
||||
App-ID: com.ryoun.musicreater.musicreater
|
||||
Version: 0.0.1
|
||||
Home-page: https://musicreater.ryoun.com/musicreater
|
||||
Author: Eilles Wan
|
||||
Author-email: W-YI_DoctorYI@outlook.com
|
||||
Summary: Musicreater is an Eilles's app that is used for creating musics in Minecraft: Bedrock Edition
|
||||
364
src/musicreater/Cmd_Msct.py
Normal file
364
src/musicreater/Cmd_Msct.py
Normal file
@@ -0,0 +1,364 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# W-YI 金羿
|
||||
# QQ 2647547478
|
||||
# 音·创 开发交流群 861684859
|
||||
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com
|
||||
# 版权所有 Team-Ryoun 金羿
|
||||
# 若需转载或借鉴 请附作者
|
||||
|
||||
|
||||
# 代码写的并非十分的漂亮,还请大佬多多包涵;本软件源代码依照Apache软件协议公开
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
import sys
|
||||
|
||||
from musicreater.msctspt.threadOpera import NewThread
|
||||
from musicreater.msctspt.bugReporter import version
|
||||
from musicreater.nmcsup.log import log
|
||||
|
||||
__version__ = version.version[1]+version.version[0]
|
||||
__author__ = 'W-YI (金羿)'
|
||||
|
||||
|
||||
log("系统工作————————加载变量及函数")
|
||||
|
||||
|
||||
print("更新执行位置...")
|
||||
|
||||
if sys.platform == 'win32':
|
||||
os.chdir(__file__[:len(__file__)-__file__[len(__file__)::-1].index('\\')])
|
||||
log("更新执行位置,当前文件位置"+__file__)
|
||||
else:
|
||||
try:
|
||||
os.chdir(__file__[:len(__file__) -
|
||||
__file__[len(__file__)::-1].index('/')])
|
||||
except:
|
||||
pass
|
||||
log("其他平台:"+sys.platform+"更新执行位置,当前文件位置"+__file__)
|
||||
print('完成!')
|
||||
|
||||
|
||||
|
||||
print('建立变量,存入内存,载入字典常量函数')
|
||||
|
||||
# 主体部分
|
||||
|
||||
# 支持多文件同时操作
|
||||
|
||||
# dataset[{ 'mainset':{ 'x':'y' }, 'musics': [ { 'set' :{ 'A':'B' } , 'note' : [ [ 'a' , b ], ] }, ] }, ]
|
||||
|
||||
# 编辑:
|
||||
# 修改主设置: dataset[第几个项目]['mainset']['什么设置'] = '设置啥'
|
||||
# 修改音乐: dataset[第几个项目]['musics'][第几个音轨]['notes'][第几个音符][音符还是时间(0,1)] = 改成啥
|
||||
# 修改音轨设置: dataset[第几个项目]['musics'][第几个音轨]['set']['什么设置'] = '设置啥'
|
||||
#
|
||||
# 新增音轨: dataset[第几个项目]['musics'].append(datasetmodelpart)
|
||||
#
|
||||
'''
|
||||
dataset=[
|
||||
{
|
||||
'mainset':{
|
||||
'PackName':"Ryoun",
|
||||
'MusicTitle':'Noname',
|
||||
'IsRepeat':False,
|
||||
'PlayerSelect':''
|
||||
},
|
||||
'musics':[
|
||||
{
|
||||
'set':{
|
||||
'EntityName':'music_support',
|
||||
'ScoreboardName':'music_support',
|
||||
'Instrument':'harp',
|
||||
'FileName':"Music"
|
||||
},
|
||||
'notes':[
|
||||
[0.0,1.0],
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
'''
|
||||
|
||||
global dataset
|
||||
|
||||
dataset = [
|
||||
{
|
||||
'mainset': {
|
||||
'PackName': "Ryoun",
|
||||
'MusicTitle': 'Noname',
|
||||
'IsRepeat': False,
|
||||
'PlayerSelect': ''
|
||||
},
|
||||
'musics': [
|
||||
{
|
||||
'set': {
|
||||
'EntityName': 'MusicSupport',
|
||||
'ScoreboardName': 'MusicSupport',
|
||||
'Instrument': 'note.harp',
|
||||
'FileName': "Music"
|
||||
},
|
||||
'notes': [
|
||||
[0.0, 1.0],
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
global is_new_file
|
||||
global is_save
|
||||
global ProjectName
|
||||
global NowMusic
|
||||
|
||||
is_new_file = True
|
||||
is_save = True
|
||||
ProjectName = ''
|
||||
NowMusic = 0
|
||||
|
||||
def DMM(): # 反回字典用于编辑
|
||||
datasetmodelpart = {
|
||||
'set': {
|
||||
'EntityName': 'MusicSupport',
|
||||
'ScoreboardName': 'MusicSupport',
|
||||
'Instrument': 'note.harp',
|
||||
'FileName': "Music"
|
||||
},
|
||||
'notes': []
|
||||
}
|
||||
return datasetmodelpart
|
||||
|
||||
print("完成")
|
||||
|
||||
# 菜单命令
|
||||
print('加载菜单命令...')
|
||||
|
||||
def exitapp(cmd):
|
||||
|
||||
log("程序正常退出", False)
|
||||
global is_save
|
||||
if is_save == False:
|
||||
if '/s' in cmd:
|
||||
saveProject()
|
||||
else:
|
||||
print("您尚未保存,请使用 /s 开关保存并退出")
|
||||
return False
|
||||
|
||||
try:
|
||||
global dataset
|
||||
del dataset
|
||||
except:
|
||||
pass
|
||||
|
||||
if '/c' in cmd:
|
||||
print("清除log(此句不载入日志)")
|
||||
try:
|
||||
if os.path.exists("./log/"):
|
||||
shutil.rmtree("./log/")
|
||||
if os.path.exists("./logs/"):
|
||||
shutil.rmtree("./logs/")
|
||||
if os.path.exists("./cache/"):
|
||||
shutil.rmtree("./cache/")
|
||||
except:
|
||||
print("无法清除日志及临时文件")
|
||||
|
||||
exit()
|
||||
|
||||
print('退出函数加载完成!')
|
||||
|
||||
print("载入文件读取函数")
|
||||
|
||||
def ReadFile(fn: str):
|
||||
from nmcsup.nmcreader import ReadFile as fileRead
|
||||
k = fileRead(fn)
|
||||
if k == False:
|
||||
log("找不到"+fn)
|
||||
return False
|
||||
else:
|
||||
return k
|
||||
|
||||
def ReadMidi(midfile: str):
|
||||
from nmcsup.nmcreader import ReadMidi as midiRead
|
||||
k = midiRead(midfile)
|
||||
if k == False:
|
||||
log("找不到"+midfile)
|
||||
return False
|
||||
else:
|
||||
return k
|
||||
|
||||
print('完成!')
|
||||
|
||||
print("载入命令函数")
|
||||
|
||||
def saveProject(cmd: list):
|
||||
global is_new_file
|
||||
if '/a' in cmd:
|
||||
log("另存项目")
|
||||
ProjectName = cmd[cmd.index('/a')+1]
|
||||
else:
|
||||
if is_new_file:
|
||||
print("初次存储请使用 /a 开关规定存储文件名")
|
||||
log("文件未保存")
|
||||
return False
|
||||
|
||||
log("存储文件:"+ProjectName)
|
||||
with open(ProjectName, 'w', encoding='utf-8') as f:
|
||||
json.dump(dataset[0], f)
|
||||
global is_save
|
||||
is_save = True
|
||||
|
||||
print('保存项目函数加载完成!')
|
||||
|
||||
def loadMusic(cmd: list):
|
||||
if '/mid' in cmd:
|
||||
th = NewThread(ReadMidi, (cmd[cmd.index('/mid')+1],))
|
||||
th.start()
|
||||
|
||||
def midiSPT(th):
|
||||
for i in th.getResult():
|
||||
datas = DMM()
|
||||
datas['notes'] = i
|
||||
dataset[0]['musics'].append(datas)
|
||||
del th
|
||||
global is_save
|
||||
is_save = False
|
||||
threading.Thread(target=midiSPT, args=(th,)).start()
|
||||
del th
|
||||
elif '/txt' in cmd:
|
||||
th = NewThread(ReadFile, (cmd[cmd.index('/txt')+1],))
|
||||
th.start()
|
||||
|
||||
def midiSPT(th):
|
||||
for i in th.getResult():
|
||||
datas = DMM()
|
||||
datas['notes'] = i
|
||||
dataset[0]['musics'].append(datas)
|
||||
del th
|
||||
global is_save
|
||||
is_save = False
|
||||
threading.Thread(target=midiSPT, args=(th,)).start()
|
||||
elif '/input' in cmd:
|
||||
datas = []
|
||||
for i in cmd[cmd.index('/input')+1:]:
|
||||
datas.append([str(i), 1.0])
|
||||
from nmcsup.trans import note2list
|
||||
datat = DMM()
|
||||
datat['notes'] = note2list(datas)
|
||||
dataset[0]['musics'].append(datat)
|
||||
del datas, datat
|
||||
global is_save
|
||||
is_save = False
|
||||
else:
|
||||
log("无参数,无法读入。")
|
||||
print("请查看帮助文件查看指令格式。")
|
||||
return False
|
||||
|
||||
print('音轨载入函数加载完成!')
|
||||
|
||||
def funBuild(cmd: list):
|
||||
if '/file' in cmd:
|
||||
from msctspt.funcOpera import makeFuncFiles
|
||||
makepath = cmd[cmd.index('/file')+1]
|
||||
if makepath[-1] != '/':
|
||||
makepath += '/'
|
||||
makeFuncFiles(dataset[0], makepath)
|
||||
elif '/directory' in cmd:
|
||||
from msctspt.funcOpera import makeFunDir
|
||||
makepath = cmd[cmd.index('/directory')+1]
|
||||
if makepath[-1] != '/':
|
||||
makepath += '/'
|
||||
makeFunDir(dataset[0], makepath)
|
||||
elif '/mcpack' in cmd:
|
||||
import zipfile
|
||||
from msctspt.funcOpera import makeFunDir
|
||||
makepath = cmd[cmd.index('/mcpack')+1]
|
||||
if makepath[-1] != '/':
|
||||
makepath += '/'
|
||||
|
||||
if not os.path.exists('./temp/'):
|
||||
os.makedirs('./temp/')
|
||||
makeFunDir(dataset[0], './temp/')
|
||||
shutil.move('./temp/'+dataset[0]['mainset']['PackName'] +
|
||||
"Pack/behavior_packs/"+dataset[0]['mainset']['PackName']+"/functions", './')
|
||||
shutil.move('./temp/'+dataset[0]['mainset']['PackName'] + "Pack/behavior_packs/" +
|
||||
dataset[0]['mainset']['PackName']+"/manifest.json", './')
|
||||
with zipfile.ZipFile(makepath+dataset[0]['mainset']['PackName']+'.mcpack', "w") as zipobj:
|
||||
for i in os.listdir('./functions/'):
|
||||
zipobj.write('./functions/'+i)
|
||||
zipobj.write('./manifest.json')
|
||||
shutil.move('./functions', './temp/')
|
||||
shutil.move('./manifest.json', './temp/')
|
||||
shutil.rmtree("./temp/")
|
||||
else:
|
||||
log("无参数,无法读入。")
|
||||
print("请查看帮助文件查看指令格式。")
|
||||
return False
|
||||
|
||||
print("函数建立函数加载完成")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def __main__():
|
||||
|
||||
if sys.platform == 'win32':
|
||||
os.system("cls")
|
||||
else:
|
||||
os.system("clear")
|
||||
|
||||
if sys.platform in ('win32', 'linux'):
|
||||
print("您当前的运行环境为标准桌面,您可以打开 Musicreater.py 运行窗口模式的 音·创")
|
||||
print("您也可以输入 win 指令在不退出命令行模式的同时打开窗口模式\n")
|
||||
|
||||
print(__author__+" 音·创 —— 当前核心版本 "+__version__+'\n')
|
||||
|
||||
nowWorkPath = os.path.split(os.path.realpath(__file__))[0]
|
||||
|
||||
while True:
|
||||
|
||||
strcmd = input("MSCT "+nowWorkPath+">")
|
||||
cmd = strcmd.lower().split(' ')
|
||||
|
||||
if cmd[0] == 'exit':
|
||||
exitapp(cmd[1:])
|
||||
elif cmd[0] == 'save':
|
||||
saveProject(cmd[1:])
|
||||
elif cmd[0] == 'load':
|
||||
loadMusic(cmd[1:])
|
||||
elif cmd[0] == 'win':
|
||||
def run(cmd):
|
||||
os.system(cmd)
|
||||
if sys.platform == 'win32':
|
||||
NewThread(run, ("python "+os.path.split(os.path.realpath(__file__))
|
||||
[0]+"/Musicreater.py",)).start()
|
||||
else:
|
||||
NewThread(run, ("python3 "+os.path.split(os.path.realpath(__file__))
|
||||
[0]+"/Musicreater.py",)).start()
|
||||
elif cmd[0] == 'chdir':
|
||||
nowWorkPath = os.path.realpath(cmd[1])
|
||||
os.chdir(nowWorkPath)
|
||||
elif cmd[0] == 'build':
|
||||
funBuild(cmd[1:])
|
||||
else:
|
||||
os.system(strcmd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
__main__
|
||||
0
src/musicreater/__init__.py
Normal file
0
src/musicreater/__init__.py
Normal file
4
src/musicreater/__main__.py
Normal file
4
src/musicreater/__main__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from musicreater.app import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
main().main_loop()
|
||||
133
src/musicreater/app.py
Normal file
133
src/musicreater/app.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
音·创(Musicreater)是由金羿(W-YI)开发的一款《我的世界》基岩版音乐生成辅助软件
|
||||
"""
|
||||
|
||||
|
||||
# W-YI 金羿
|
||||
# QQ 2647547478
|
||||
# 音·创 开发交流群 861684859
|
||||
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com
|
||||
# 版权所有 Team-Ryoun 金羿
|
||||
# 若需转载或借鉴 请附作者
|
||||
|
||||
|
||||
# 代码写的并非十分的漂亮,还请大佬多多包涵;本软件源代码依照Apache软件协议公开
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import toga
|
||||
from toga.style import Pack
|
||||
from toga.style.pack import COLUMN, ROW
|
||||
|
||||
from musicreater.Cmd_Msct import *
|
||||
from musicreater.msctspt.bugReporter import version
|
||||
|
||||
from musicreater.resources.ChineseLang import LANGUAGE
|
||||
|
||||
|
||||
|
||||
__version__ = version.version[1]+version.version[0]
|
||||
__author__ = 'W-YI (金羿)'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
os.chdir(__file__[:len(__file__)-__file__[len(__file__)::-1].index('\\')])
|
||||
log("更新执行位置,当前文件位置"+__file__)
|
||||
else:
|
||||
try:
|
||||
os.chdir(__file__[:len(__file__) -
|
||||
__file__[len(__file__)::-1].index('/')])
|
||||
except:
|
||||
pass
|
||||
log("其他平台:"+sys.platform+"更新执行位置,当前文件位置"+__file__)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Musicreater(toga.App):
|
||||
'''音·创 本体\n
|
||||
W-YI 金羿\n
|
||||
QQ 2647547478\n
|
||||
音·创 开发交流群 861684859\n
|
||||
Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com\n
|
||||
版权所有 Team-Ryoun 金羿\n
|
||||
若需转载或借鉴 请附作者\n
|
||||
'''
|
||||
|
||||
|
||||
|
||||
def startup(self):
|
||||
|
||||
|
||||
# Start to draw the window
|
||||
|
||||
main_box = toga.Box(style=Pack(direction=COLUMN))
|
||||
|
||||
self.noticeLabel = toga.Label('MSCT >>>',style=Pack(padding=(0, 5)))
|
||||
|
||||
self.inputBox = toga.TextInput(style=Pack(flex=1))
|
||||
#dispImage = toga.ImageView("./resources/oddevenmatrix.png")
|
||||
|
||||
cmd_box = toga.Box(style=Pack(direction=ROW, padding=5))
|
||||
|
||||
cmd_box.add(self.noticeLabel)
|
||||
cmd_box.add(self.inputBox)
|
||||
# cmd_box.add(dispImage)
|
||||
|
||||
button = toga.Button(
|
||||
LANGUAGE['main']['run'],
|
||||
on_press=self.showMessage,
|
||||
style=Pack(padding=5)
|
||||
)
|
||||
|
||||
|
||||
main_box.add(cmd_box)
|
||||
main_box.add(button)
|
||||
|
||||
|
||||
self.main_window = toga.MainWindow(title=self.formal_name)
|
||||
self.main_window.content = main_box
|
||||
self.main_window.show()
|
||||
|
||||
self.main_window.info_dialog('',"{} {} —— {} {}".format(__author__,LANGUAGE['main']['name'],LANGUAGE['main']['version'],__version__))
|
||||
|
||||
self.nowWorkPath = os.path.split(os.path.realpath(__file__))[0]
|
||||
|
||||
|
||||
def showMessage(self, widget):
|
||||
|
||||
strcmd = self.inputBox.value
|
||||
|
||||
cmd = strcmd.lower().split(' ')
|
||||
|
||||
if cmd[0] == 'exit':
|
||||
if exitapp(cmd[1:]) == False:
|
||||
self.main_window.info_dialog('',LANGUAGE['command']['FormatError'])
|
||||
elif cmd[0] == 'save':
|
||||
if saveProject(cmd[1:]) == False:
|
||||
self.main_window.info_dialog('',LANGUAGE['command']['FormatError'])
|
||||
elif cmd[0] == 'load':
|
||||
if loadMusic(cmd[1:]) == False:
|
||||
self.main_window.info_dialog('',LANGUAGE['command']['FormatError'])
|
||||
elif cmd[0] == 'chdir':
|
||||
self.main_window.info_dialog('',LANGUAGE['command']['NotAvailable'])
|
||||
return
|
||||
nowWorkPath = os.path.realpath(cmd[1])
|
||||
os.chdir(nowWorkPath)
|
||||
elif cmd[0] == 'build':
|
||||
if funBuild(cmd[1:]) == False:
|
||||
self.main_window.info_dialog('',LANGUAGE['command']['FormatError'])
|
||||
else:
|
||||
return
|
||||
os.system(strcmd)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
return Musicreater()
|
||||
141
src/musicreater/fcwslib/__init__.py
Normal file
141
src/musicreater/fcwslib/__init__.py
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__version__ = '0.0.1'
|
||||
__all__ = ['run_server', 'subscribe', 'unsubscribe', 'send_command', 'tellraw']
|
||||
__author__ = 'Fuckcraft <https://gitee.com/fuckcraft>'
|
||||
|
||||
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()
|
||||
|
||||
2
src/musicreater/log/2021-12-31 00_13_19.msct.log
Normal file
2
src/musicreater/log/2021-12-31 00_13_19.msct.log
Normal file
@@ -0,0 +1,2 @@
|
||||
00:13:19 更新执行位置,当前文件位置F:\W-YI\Programming\音·创\程序\src\musicreater\Cmd_Msct.py
|
||||
00:13:19 更新执行位置,当前文件位置F:\W-YI\Programming\音·创\程序\src\musicreater\app.py
|
||||
173
src/musicreater/msctspt/MSCT Dev Log.txt
Normal file
173
src/musicreater/msctspt/MSCT Dev Log.txt
Normal file
@@ -0,0 +1,173 @@
|
||||
音·创(Musicreater)是由金羿(W-YI)开发的一款《我的世界》基岩版音乐生成辅助软件
|
||||
本软件源代码依照Apache软件协议公开。
|
||||
|
||||
Copyright © W-YI 2021
|
||||
|
||||
本软件是金羿前作函数音创和世界音创的集合版本,同时增加了大量功能更新。
|
||||
|
||||
|
||||
To-Do
|
||||
1.可以导出自定义的结构文件用于存储要导入地图中的结构
|
||||
2.进度条
|
||||
3.可以将音乐写入音符盒(红乐)
|
||||
4.更换tk库为briefcase库,支持安卓系统
|
||||
5.支持自动给音符盒绑定更多的音色
|
||||
6.可以由.schematic文件导入地图,亦可反向处理
|
||||
7.支持自定义指令方块区域的长宽高等
|
||||
8.支持自定义创建websockeet服务器播放音乐(感谢由 Fuckcraft <https://github.com/fuckcraft> “鸣凤鸽子”等 带来的我的世界websocket服务器功能)
|
||||
9.支持使用红石播放指令音乐
|
||||
10.支持采用延时的播放器
|
||||
11.支持使用bdx导出结构
|
||||
12.支持采用tp的方法播放
|
||||
13.支持识别曲谱图片解析音乐
|
||||
14.支持使用瀑布流的方式播放音乐
|
||||
15.帮助菜单
|
||||
16.多语言
|
||||
17.支持自动搜寻地图目录位置(网易&微软)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
新更新日志
|
||||
|
||||
Beta 0.0.4.3
|
||||
2021 11 3~2021 12 26
|
||||
1.不断改进包以及代码可读性
|
||||
2.修正部分源码错误
|
||||
3.修正部分格式错误
|
||||
4.加强对Linux系统的支持
|
||||
5.新增命令行模式
|
||||
6.代码中新增大量注释
|
||||
|
||||
|
||||
Beta 0.0.4 ~ Beta 0.0.4.2
|
||||
2021 11 20 ~ 2021 11 21
|
||||
1.完全支持Linux系统
|
||||
2.支持以.RyStruct导出结构
|
||||
3.修复大量bug
|
||||
4.支持拖拽打开(参数1为.msct文件)
|
||||
|
||||
|
||||
Beta 0.0.3.1~0.0.3.5
|
||||
2021 11 1~2021 11 2
|
||||
1.更新部分提示信息使之更加科学
|
||||
2.强制性限制不得使用非Win32平台打开此程序
|
||||
3.支持在Windwos7上使用此程序(发现错误并解决:DLL缺失MSVCP140.dll)
|
||||
4.开始对结构导出进行部分支持
|
||||
5.发现红乐写入的错误,正在排查修复
|
||||
|
||||
|
||||
|
||||
|
||||
Beta 0.0.3
|
||||
2021 10 29 ~ 2021 10 31
|
||||
1.修改部分窗口排版
|
||||
2.修复指令载入地图的结构的错误
|
||||
3.修复指令生成出现的指令错误(感谢 昀梦<QQ1515399885> 找出bug并指正)
|
||||
4.支持生成红石音乐(以音符盒存储的音乐),并写入地图
|
||||
5.修复了生成指令音乐导致的错误
|
||||
6.修复bdx文件y轴过长导致无法生成完毕的错误,现在bdx的y轴为200格
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Beta 0.0.2
|
||||
2021 10 25
|
||||
1.修复了邮件发送错误报告无法生成压缩包的问题
|
||||
2.修复了导入音轨时无法获得进程返回值的问题
|
||||
3.修复了.bdx文件生成时无法选择文件的问题
|
||||
4.修复了生成指令音乐(计分板)没有起始方块的问题
|
||||
5.新增了创建Websocket的功能,可以在localhost:8080创建websocket服务器播放音乐(感谢由 Fuckcraft <https://gitee.com/fuckcraft> “鸣凤鸽子”等 带来的我的世界websocket服务器功能(fcwslib) )
|
||||
6.解决了打包成可执行文件时无法正常退出的问题
|
||||
|
||||
|
||||
|
||||
Beta 0.0.1
|
||||
2021 10月
|
||||
1.支持生成.bdx文件(感谢由 Charlie_Ping “查理平” 带来的bdx转换功能)
|
||||
2.逐步增强对安卓系统的支持
|
||||
3.逐步放弃对Windows的强行要求
|
||||
4.逐步提升性能,增加多线程
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Alpha部分更新日志
|
||||
|
||||
Alpha 0.0.0
|
||||
2021 8 20
|
||||
1.集合了 函数音创0.1.4.1 与 世界音创Beta0.0.1 的功能于本应用
|
||||
2.新增了可以生成 .mcpack 包的方法
|
||||
|
||||
Alpha 0.0.1
|
||||
2021 8 25
|
||||
1.新增两个彩蛋(就是函数音创命令行模式的彩蛋
|
||||
|
||||
Alpha 0.0.1.1
|
||||
2021 8 25
|
||||
1.修复大量已知问题
|
||||
2.修复了部分彩蛋bug,但是程序仍然不会正常退出
|
||||
3.菜单界面优化
|
||||
|
||||
Alpha 0.0.1.2
|
||||
2021.8.29
|
||||
1.修复大量已知问题
|
||||
2.现在可以操作指令文件了
|
||||
3.窗口界面优化
|
||||
|
||||
Alpha 0.0.2
|
||||
2021 9 5
|
||||
1.修复部分已知问题
|
||||
2.指令链导入之时仅生成链式方块且允许折转
|
||||
3.[Dev]正在逐步支持结构导出
|
||||
|
||||
Alpha 0.0.3
|
||||
2021 9 7
|
||||
1.修复指令链转入世界的摆放错误
|
||||
2.指令存储的音乐(包括函数)支持不同玩家不同的播放
|
||||
3.支持播放进度条
|
||||
4.删除彩蛋任务栏图标
|
||||
4.[Dev]已确定导出结构格式
|
||||
|
||||
Alpha 0.0.3.1
|
||||
2021 9 11
|
||||
1.取消输入玩家选择器时不会出现bug了
|
||||
2.删除日志文件修改为删除临时文件
|
||||
3.可以删除用于确认档案存在的文件了
|
||||
|
||||
Alpha 0.0.4
|
||||
2021 10 4-5
|
||||
1.可以将大函数导入世界(以一条链执行多个函数的方式)
|
||||
2.关闭了试听音乐的功能,但是保留其函数于funOpera.py中
|
||||
3.修改部分代码,减少更多bug
|
||||
4.发现指令链转入世界的摆放错误,但是没改正
|
||||
|
||||
1.0.3
|
||||
2021 10 5-6
|
||||
1.解决一些已知问题
|
||||
2.解决了文件读取造成的字符编码问题
|
||||
3.使用PyPinyin库将汉字转化为拼音首字母
|
||||
|
||||
Alpha 0.0.4.1
|
||||
2021 10 9
|
||||
1.将清除日志功能设置为结束后统一清除,避免了清除过程中文件占用导致的问题
|
||||
|
||||
Alpha 0.0.5
|
||||
2021 10 10
|
||||
1.支持使用邮件方式发送错误报告(日志)
|
||||
|
||||
Alpha 0.0.5.1
|
||||
1.修复了邮件发送错误报告无法发送的问题
|
||||
2.修复了打包成.exe文件之后无法正常退出的问题
|
||||
|
||||
|
||||
|
||||
|
||||
0
src/musicreater/msctspt/__init__.py
Normal file
0
src/musicreater/msctspt/__init__.py
Normal file
215
src/musicreater/msctspt/bdxOpera_CP.py
Normal file
215
src/musicreater/msctspt/bdxOpera_CP.py
Normal file
@@ -0,0 +1,215 @@
|
||||
import os
|
||||
import brotli
|
||||
|
||||
'''感谢由 Charlie_Ping “查理平” 带来的bdx转换代码'''
|
||||
|
||||
|
||||
class BdxConverter:
|
||||
__header = "BD@"
|
||||
__bin_header = b"BDX"
|
||||
__generator_author = b"&Charlie_Ping"
|
||||
|
||||
keys = {
|
||||
# x--, x++, addSmallX(-128~127), addX(-32768~32767), addBigX(-2147483648~2147483647)
|
||||
"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"],
|
||||
"end": b"\x58",
|
||||
"isSigned": b"\x5a",
|
||||
"placeCommandBlockWithData": b"\x1b",
|
||||
"placeBlock": b"\x07"
|
||||
}
|
||||
|
||||
def __init__(self, file_path: str, author: str, blocks):
|
||||
self.author = author
|
||||
self.blocks = blocks
|
||||
self.file_path = file_path
|
||||
self.direction = [0, 0, 0]
|
||||
self.block_type = self.get_block_type
|
||||
self.__file = self.create_and_upload_file
|
||||
|
||||
@property
|
||||
def get_block_type(self):
|
||||
"""
|
||||
blocks
|
||||
[
|
||||
{
|
||||
"direction": [x: int, y: int, z: int],
|
||||
block_name: str,
|
||||
particular_value: int,
|
||||
}
|
||||
]
|
||||
:return: list 给出的所有方块种类名称
|
||||
"""
|
||||
block_type = set()
|
||||
for block in self.blocks:
|
||||
block_type.add(block["block_name"])
|
||||
block_type = list(block_type)
|
||||
return block_type
|
||||
|
||||
@property
|
||||
def create_and_upload_file(self):
|
||||
"""
|
||||
(瞎用property? 害怕
|
||||
创建一个bdx文件
|
||||
要close!
|
||||
:return: 一个文件对象
|
||||
"""
|
||||
_dir = os.path.dirname(self.file_path)
|
||||
if not os.path.isdir(_dir):
|
||||
os.makedirs(_dir)
|
||||
_bytes = self.__bin_header
|
||||
_bytes += b"\x00"
|
||||
_bytes += self.author.encode("utf-8") + self.__generator_author
|
||||
for i in self.block_type:
|
||||
_bytes += b"\x00\x01"
|
||||
_bytes += bytes(i, encoding="utf-8")
|
||||
_bytes += b"\x00"
|
||||
_bytes += self.upload_blocks()
|
||||
_bytes += b"X"
|
||||
with open(self.file_path, "w+") as f:
|
||||
f.write("BD@")
|
||||
f.close()
|
||||
with open(self.file_path, "ab+") as f:
|
||||
f.write(brotli.compress(_bytes))
|
||||
f.close()
|
||||
return
|
||||
def upload_blocks(self):
|
||||
"""
|
||||
计算差值
|
||||
写入移动过程
|
||||
写入方块
|
||||
更新差值
|
||||
:return:
|
||||
"""
|
||||
_types = b""
|
||||
for block in self.blocks:
|
||||
# print(f"当前方块:{block['block_name']}, 位置: {block['direction']}]")
|
||||
diff = self.move_pointer(self.direction, block["direction"])
|
||||
_types += diff
|
||||
if block["block_name"] in ["command_block",
|
||||
"chain_command_block",
|
||||
"repeating_command_block"]:
|
||||
_types += self.obtain_command_block(block)
|
||||
else:
|
||||
_types += self.obtain_universal_block(block)
|
||||
self.direction = block["direction"]
|
||||
return _types
|
||||
|
||||
def move_pointer(self, direction: list, new_direction):
|
||||
"""
|
||||
给出 两个[x, y, z]坐标,返回pointer的移动过程
|
||||
:param direction: 坐标 1
|
||||
:param new_direction: 坐标 2
|
||||
:return: bytes
|
||||
"""
|
||||
_bytes = b""
|
||||
for i, sign in enumerate(["x", "y", "z"]):
|
||||
# print(f"<{sign}> 新-旧={new_direction[i]-direction[i]}")
|
||||
distance = new_direction[i] - direction[i]
|
||||
if distance == 0:
|
||||
# print("距离是0?跳过了")
|
||||
continue
|
||||
_bytes += self.obtain_pointer_type(distance, sign)
|
||||
# print(f"向 {sign} 运动了 {distance} 格子")
|
||||
return _bytes
|
||||
|
||||
@classmethod
|
||||
def obtain_pointer_type(cls, num: int, coordinate: str):
|
||||
"""
|
||||
|
||||
用于确定辅助玩家以某一数据类型走指定长度
|
||||
|
||||
-1 -> 0
|
||||
1 -> 1
|
||||
[128, 127] -> 2
|
||||
[-32768, 32767] -> 3
|
||||
[-2147483648, 2147483647] -> 4
|
||||
:param num:
|
||||
:param coordinate: 坐标轴种类,x y 或 z
|
||||
:return:
|
||||
"""
|
||||
if num == 0:
|
||||
return
|
||||
pointer = 0
|
||||
condition = (num != -1, # byte=0, pointer=1
|
||||
num < -1 or num > 1, # byte=1, pointer=2
|
||||
num < -128 or num > 127, # byte=2, pointer=3
|
||||
num < -32768 or num > 32767, # byte=4, pointer=4
|
||||
)
|
||||
for i in condition:
|
||||
if i:
|
||||
pointer += 1
|
||||
pointer_type = cls.keys[coordinate][pointer]
|
||||
|
||||
byte_len = 2 ** (pointer - 2)
|
||||
if byte_len >= 1:
|
||||
num_byte = num.to_bytes(byte_len, byteorder="big", signed=True)
|
||||
return pointer_type + num_byte
|
||||
return pointer_type
|
||||
|
||||
def obtain_universal_block(self, block):
|
||||
"""
|
||||
给定一个方块, 返回此方块在这个bdx中的id和方块data
|
||||
:param block: {block_name: str,particular_value: int}
|
||||
:return: bytes
|
||||
"""
|
||||
block_id = b"\x07" + self.block_type.index(block["block_name"]).to_bytes(2, byteorder="big", signed=False)
|
||||
particular_value = block["particular_value"].to_bytes(2, byteorder="big", signed=False)
|
||||
block_header = block_id + particular_value
|
||||
return block_header
|
||||
|
||||
def obtain_command_block(self, block):
|
||||
"""
|
||||
给定一个命令方块,返回命令方块各种数据
|
||||
:param block: {
|
||||
"direction": [x: int, y: int, z: int]
|
||||
"block_name": str,
|
||||
"particular_value": int,
|
||||
"impluse": int, # unsigned_int32
|
||||
"command": str,
|
||||
"customName": str,
|
||||
"lastOutput": str, # 没特殊要求写个\x00就得了
|
||||
"tickdelay": int, # int32
|
||||
"executeOnFirstTick": int, # 1 bytes
|
||||
"trackOutput": int, # 1 bytes
|
||||
"conditional": int, # 1 bytes
|
||||
"needRedstone": int # 1 bytes
|
||||
}
|
||||
:return: bytes of command_block
|
||||
"""
|
||||
|
||||
block_id = b"\x1b" + self.block_type.index(block["block_name"]).to_bytes(2, byteorder="big", signed=False)
|
||||
particular_value = block["particular_value"].to_bytes(2, byteorder="big", signed=False)
|
||||
block_header = block_id + particular_value
|
||||
for i in [
|
||||
block["impluse"].to_bytes(4, byteorder="big", signed=False),
|
||||
bytes(block["command"], encoding="utf-8") + b"\x00",
|
||||
bytes(block["customName"], encoding="utf-8") + b"\x00",
|
||||
bytes(block["lastOutput"], encoding="utf-8") + b"\x00",
|
||||
block["tickdelay"].to_bytes(4, byteorder="big", signed=True),
|
||||
block["executeOnFirstTick"].to_bytes(1, byteorder="big"),
|
||||
block["trackOutput"].to_bytes(1, byteorder="big"),
|
||||
block["conditional"].to_bytes(1, byteorder="big"),
|
||||
block["needRedstone"].to_bytes(1, byteorder="big")
|
||||
]:
|
||||
block_header += i
|
||||
return block_header
|
||||
|
||||
if __name__ == '__main__':
|
||||
block = [{"direction": [-1, -1, -1], "block_name": "concrete", "particular_value": 5},
|
||||
{"direction": [1, 5, 1], "block_name": "stained_glass", "particular_value": 7},
|
||||
{"direction": [2, 4, 1], "block_name": "command_block", "particular_value": 3,
|
||||
"impluse": 0,
|
||||
"command": "say A generator test",
|
||||
"customName": "test",
|
||||
"lastOutput": "",
|
||||
"tickdelay": 24,
|
||||
"executeOnFirstTick": 0,
|
||||
"trackOutput": 0,
|
||||
"conditional": 0,
|
||||
"needRedstone": 1
|
||||
},
|
||||
{"direction": [3, 4, 1], "block_name": "concrete", "particular_value": 6},
|
||||
{"direction": [-123412133, 4, 1], "block_name": "concrete", "particular_value": 7}]
|
||||
bdx = BdxConverter("./test02.bdx", "Charlie_Ping",block)
|
||||
134
src/musicreater/msctspt/bugReporter.py
Normal file
134
src/musicreater/msctspt/bugReporter.py
Normal file
@@ -0,0 +1,134 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
'''提供错误报告的基本操作及方法 顺便提供版本更新、安装库等功能'''
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeZip(sourceDir, outFilename,compression = 8,exceptFile = None):
|
||||
'''使用compression指定的算法打包目录为zip文件\n
|
||||
默认算法为DEFLATED(8),可用算法如下:\n
|
||||
STORED = 0\n
|
||||
DEFLATED = 8\n
|
||||
BZIP2 = 12\n
|
||||
LZMA = 14\n
|
||||
'''
|
||||
import os, zipfile
|
||||
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;
|
||||
print(filename)
|
||||
pathfile = os.path.join(parent, filename)
|
||||
arcname = pathfile[pre_len:].strip(os.path.sep) #相对路径
|
||||
zipf.write(pathfile, arcname)
|
||||
|
||||
zipf.close()
|
||||
del zipf,pre_len
|
||||
#以上函数节选并修改自 正在攀登的小蜗牛 的博客:https://blog.csdn.net/qq_21127151/article/details/107503942
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class report():
|
||||
'''发送报告以及相应的任务处理'''
|
||||
def __init__(self,senderName:str = 'Unknown',senderContact:str = 'None',describetion:str = ''):
|
||||
''':param senderName 发送者名称
|
||||
:param senderContact 发送者联系方式
|
||||
:param describetion 问题描述'''
|
||||
self.senderName = senderName;
|
||||
self.senderContact = senderContact;
|
||||
self.describetion = describetion;
|
||||
if not self.senderName :
|
||||
self.senderName = 'Unknown';
|
||||
if not self.senderContact :
|
||||
self.senderContact = 'None';
|
||||
|
||||
|
||||
|
||||
def emailReport(self):
|
||||
'''使用E-mail方法发送当前的日志和临时文件等'''
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText;
|
||||
from email.mime.multipart import MIMEMultipart;
|
||||
from email.header import Header;
|
||||
from musicreater.nmcsup.log import log
|
||||
log("发送错误报告")
|
||||
import os;
|
||||
log("添加标题与正文")
|
||||
msg = MIMEMultipart();
|
||||
#发送者与接收者显示名称
|
||||
msg["From"] = Header(self.senderName,'utf-8');
|
||||
msg["To"] = Header("W-YI (QQ2647547478)",'utf-8');
|
||||
#标题
|
||||
msg["Subject"] = '音·创 - 来自 '+self.senderName+' 的错误报告';
|
||||
#正文
|
||||
msg.attach(MIMEText("来自"+self.senderName+"( "+self.senderContact+" )的错误描述:\n"+self.describetion,'plain','utf-8'));
|
||||
log("添加完毕,正在生成压缩包...")
|
||||
makeZip("./","Temps&Logs.zip",exceptFile="Temps&Logs.zip");
|
||||
attafile=MIMEText(open("Temps&Logs.zip",'rb').read(),"base64",'gb2312');
|
||||
attafile["Content-Type"] = 'application/octet-stream';
|
||||
attafile["Content-Disposition"] = 'attachment;filename="BugReport_from_'+self.senderName+'.zip"';
|
||||
msg.attach(attafile);
|
||||
log("完毕,准备发送")
|
||||
try:
|
||||
smtp = smtplib.SMTP()
|
||||
smtp.connect("smtp.163.com");
|
||||
#SIQQKQQYCZRVIDFJ是授权密码
|
||||
smtp.login("RyounDevTeam@163.com","SIQQKQQYCZRVIDFJ");
|
||||
smtp.sendmail("RyounDevTeam@163.com",["RyounDevTeam@163.com",],msg.as_string())
|
||||
log("错误汇报邮件已发送")
|
||||
except smtplib.SMTPException as e:
|
||||
log("错误汇报邮件发送失败:\n"+str(e));
|
||||
log("清空内存和临时文件")
|
||||
del msg,attafile
|
||||
os.remove("./Temps&Logs.zip")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class version:
|
||||
|
||||
libraries = ('mido','amulet','amulet-core','amulet-nbt','piano_transcription_inference','pypinyin','briefcase','toga','pyinstaller','py7zr','websockets','torch')
|
||||
'''当前开发所需库'''
|
||||
|
||||
version = ('0.0.0','Gamma',)
|
||||
'''当前版本'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
self.libraries = version.libraries
|
||||
'''当前开发所需库'''
|
||||
|
||||
self.version = version.version
|
||||
'''当前版本'''
|
||||
|
||||
def installLibraries(self):
|
||||
'''安装全部开发用库'''
|
||||
from sys import platform
|
||||
import os
|
||||
if platform == 'win32':
|
||||
import shutil
|
||||
try:
|
||||
shutil.rmtree(os.getenv('APPDATA')+'\\Musicreater\\')
|
||||
except:
|
||||
pass;
|
||||
for i in self.libraries:
|
||||
print("安装库:"+i)
|
||||
os.system("python -m pip install "+i+" -i https://pypi.tuna.tsinghua.edu.cn/simple")
|
||||
elif platform == 'linux':
|
||||
os.system("sudo apt-get install python3-pip")
|
||||
os.system("sudo apt-get install python3-tkinter")
|
||||
for i in self.libraries:
|
||||
print("安装库:"+i)
|
||||
os.system("sudo python3 -m pip install "+i+" -i https://pypi.tuna.tsinghua.edu.cn/simple")
|
||||
|
||||
215
src/musicreater/msctspt/funcOpera.py
Normal file
215
src/musicreater/msctspt/funcOpera.py
Normal file
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""音·创 的函数操作和一些其他功能"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def delPart(Data,starter,ender,includeStart :bool= True,includend :bool= True):
|
||||
'''删除序列从starter物件到ender物件之间的部分\n
|
||||
includeStart与inclodend分别控制此函数是否包括starter和ender物件所在部分,默认为真\n
|
||||
starter与ender若为None则默认从首或尾开始'''
|
||||
try:
|
||||
if starter == None:
|
||||
includeStart = True;
|
||||
starter = Data[0];
|
||||
if ender == None:
|
||||
includend = True;
|
||||
ender = Data[len(Data)-1];
|
||||
if includend:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):len(Data)-Data[len(Data)::-1].index(ender)];
|
||||
else:
|
||||
return Data[Data.index(starter)+1:len(Data)-Data[len(Data)::-1].index(ender)];
|
||||
else:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):len(Data)-Data[len(Data)::-1].index(ender)-1];
|
||||
else:
|
||||
return Data[Data.index(starter)+1:len(Data)-Data[len(Data)::-1].index(ender)-1];
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
def keepart(Data,starter,ender,includeStart :bool= True,includend :bool= True):
|
||||
'''保留序列从starter物件到ender物件之间的部分\n
|
||||
includeStart与inclodend分别控制此函数是否包括starter和ender物件所在部分,默认为真\n
|
||||
starter与ender若为None则默认从首或尾开始'''
|
||||
try:
|
||||
if starter == None:
|
||||
includeStart = True;
|
||||
starter = Data[0];
|
||||
if ender == None:
|
||||
includend = True;
|
||||
ender = Data[len(Data)-1];
|
||||
if includend:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):Data.index(ender)+1];
|
||||
else:
|
||||
return Data[Data.index(starter)+1:Data.index(ender)+1];
|
||||
else:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):Data.index(ender)];
|
||||
else:
|
||||
return Data[Data.index(starter)+1:Data.index(ender)];
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def lenFunction(fun) -> int:
|
||||
'''取得函数指令部分长度,即忽略#开头的注释'''
|
||||
try:
|
||||
l = 0;
|
||||
for i in fun:
|
||||
if i.replace(" ",'')[0] == '#':
|
||||
l += 1;
|
||||
return len(fun)-l;
|
||||
except:
|
||||
return -1;
|
||||
|
||||
|
||||
|
||||
def funSplit(bigFile,maxCmdLen : int = 10000 ):
|
||||
'''分割bigFile大的函数文件,bigFile需要读入文件流\n
|
||||
返回的部分,每行指令皆带有行尾换行符\\n\n
|
||||
返回-1为大小低于maxCmdLen最长函数指令长度'''
|
||||
bigFile = bigFile.readlines()
|
||||
if lenFunction(bigFile) < maxCmdLen:
|
||||
return -1;
|
||||
part = [];
|
||||
parts = [];
|
||||
l = 0;
|
||||
for i in bigFile:
|
||||
if i.replace(" ",'')[0] == '#':
|
||||
part.append(i+'\n');
|
||||
else:
|
||||
part.append(i+'\n');
|
||||
l += 1;
|
||||
if l >= 10000:
|
||||
parts.append(part)
|
||||
part = [];
|
||||
l = 0;
|
||||
return parts;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeFuncFiles(musicset, path='./'):
|
||||
from musicreater.nmcsup.log import log
|
||||
'''在指定目录下生成函数文件'''
|
||||
from musicreater.nmcsup.trans import Note2Cmd
|
||||
commands = []
|
||||
starts = []
|
||||
log("=========================正在在此处生成文件:"+path)
|
||||
maxlen = -1
|
||||
for i in range(len(musicset['musics'])):
|
||||
log('写入第'+str(i)+'个数据')
|
||||
commands.append("scoreboard players add @e[name=\""+musicset['musics'][i]['set']['EntityName']+"\"] "+musicset['musics'][i]['set']['ScoreboardName']+" 1\n")
|
||||
commands.append("execute @e[name=\""+musicset['musics'][i]['set']['EntityName'] +"\",scores={"+musicset['musics'][i]['set']['ScoreboardName']+"=1..10}] ~~~ title @a"+musicset['mainset']['PlayerSelect']+" title "+musicset['mainset']['MusicTitle']+"\n")
|
||||
commands.append("execute @e[name=\""+musicset['musics'][i]['set']['EntityName'] +"\",scores={"+musicset['musics'][i]['set']['ScoreboardName']+"=1..10}] ~~~ title @a"+musicset['mainset']['PlayerSelect']+" subtitle 本函数乐曲由§b§l凌云§r§3函数音乐创建§r生成\n")
|
||||
if len(musicset['musics'][i]['notes']) > maxlen:
|
||||
maxlen = len(musicset['musics'][i]['notes'])
|
||||
starts.append("scoreboard objectives add " +musicset['musics'][i]['set']['ScoreboardName']+" dummy\n")
|
||||
starts.append("summon armor_stand " +musicset['musics'][i]['set']['EntityName']+'\n')
|
||||
with open(path+musicset['mainset']['MusicTitle']+'_Part'+str(i)+'.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(Note2Cmd(musicset['musics'][i]['notes'],musicset['musics'][i]['set']['ScoreboardName'],musicset['musics'][i]['set']['Instrument'],musicset['mainset']['PlayerSelect'],True))
|
||||
if musicset['mainset']['IsRepeat']:
|
||||
log("增加重复语句")
|
||||
for i in range(len(musicset['musics'])):
|
||||
commands.append("execute @e[name=\""+musicset['musics'][i]['set']['EntityName']+"\",scores={"+musicset['musics'][i]['set']['ScoreboardName']+"="+str((maxlen+2)*10)+"}] ~~~ scoreboard players set @e[name=\""+musicset['musics'][i]['set']['EntityName']+"\"] "+musicset['musics'][i]['set']['ScoreboardName']+" -1\n")
|
||||
log("增加版权语句")
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
starts.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
log("写入支持文件")
|
||||
with open(path+musicset['mainset']['MusicTitle']+'_Support.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(commands)
|
||||
log("写入开始文件")
|
||||
with open(path+'Start_'+musicset['mainset']['MusicTitle']+'.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(starts)
|
||||
del commands, starts, maxlen
|
||||
log("完成============================")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeFunDir(musicset, path='./'):
|
||||
from musicreater.nmcsup.log import log
|
||||
'''在指定目录下生成函数包文件夹'''
|
||||
import os
|
||||
import uuid
|
||||
log("=============================生成函数包文件夹")
|
||||
# note,packname="Ryoun",FileName="Music",EntityName_='music_support',ScoreboardName_='music_support',MusicTitle_='Noname',PlayerSelect_='',Repeat_=False,Instrument_='harp'
|
||||
try:
|
||||
os.makedirs(path+musicset['mainset']['PackName'] +"Pack/behavior_packs/"+musicset['mainset']['PackName']+"/functions")
|
||||
log("已创建目录"+path+musicset['mainset']['PackName'] +"Pack/behavior_packs/"+musicset['mainset']['PackName']+"/functions")
|
||||
except:
|
||||
log("目录已有无需创建")
|
||||
pass
|
||||
# 判断文件皆存在
|
||||
if not(os.path.exists(path+musicset['mainset']['PackName']+"Pack/world_behavior_packs.json") and os.path.exists(path+musicset['mainset']['PackName']+"Pack/behavior_packs/"+musicset['mainset']['PackName']+"/manifest.json")):
|
||||
log("创建manifest.json以及world_behavior_packs.json")
|
||||
behaviorUuid = uuid.uuid4()
|
||||
with open(path+musicset['mainset']['PackName']+"Pack/world_behavior_packs.json", "w") as f:
|
||||
f.write("[\n {\"pack_id\": \"" + str(behaviorUuid) +"\",\n \"version\": [ 0, 0, 1 ]}\n]")
|
||||
with open(path+musicset['mainset']['PackName']+"Pack/behavior_packs/"+musicset['mainset']['PackName']+"/manifest.json", "w") as f:
|
||||
f.write("{\n \"format_version\": 1,\n \"header\": {\n \"description\": \""+musicset['mainset']['PackName']+" Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \""+musicset['mainset']['PackName']+"Pack\",\n \"uuid\": \"" + str(behaviorUuid) + "\"\n },\n \"modules\": [\n {\n \"description\": \""+musicset['mainset']['PackName']+" Pack : behavior pack\",\n \"type\": \"data\",\n \"version\": [ 0, 0, 1 ],\n \"uuid\": \"" + str(uuid.uuid4()) + "\"\n }\n ]\n}")
|
||||
makeFuncFiles(musicset, path+musicset['mainset']['PackName'] +"Pack/behavior_packs/"+musicset['mainset']['PackName']+"/functions/")
|
||||
log("完成============================")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
这里是往事,用于记载一些用不到的功能
|
||||
|
||||
#存在于 Musicreater.py 播放(试听)音乐
|
||||
def PlayNote(Notes, t=480): # Notes是音符列表,t是一拍占有的毫秒数
|
||||
tkinter.messagebox.showinfo(title='提示!', message="播放发音不一定标准\n说不定还会坏音响/(ㄒoㄒ)/~~qwq\n请注意。")
|
||||
import winsound
|
||||
import time
|
||||
from nmcsup.trans import mcnote2freq
|
||||
Notes = mcnote2freq(Notes)
|
||||
for frequency, duration in Notes:
|
||||
log("播放:"+str([int(frequency), int(duration*t)]))
|
||||
if int(frequency) != 0:
|
||||
winsound.Beep(int(frequency), int(duration*t))
|
||||
elif int(frequency) == 0:
|
||||
time.sleep(duration*t/1000)
|
||||
|
||||
#同上,执行播放命令
|
||||
def PlayOne():
|
||||
log("试听")
|
||||
tkinter.messagebox.showwarning(title="警告⚠", message="试听音质可能引起您的不适,更可能引起您的扬声器的不适,请酌情播放。")
|
||||
global NowMusic
|
||||
PlayNote(dataset[0]['musics'][NowMusic]['notes'])
|
||||
|
||||
|
||||
|
||||
#同上,是早期 MinecraftMusicFunctionMaker.py (函数音创)的代码转移至音·创时的注解
|
||||
n2c(dataset[0]['musics'][i]['notes'],EntityName=dataset[0]['musics'][i]['set']['EntityName'],ScoreboardName=dataset[0]['musics'][i]['set']['ScoreboardName'],PlayerSelect=dataset[0]['mainset']['PlayerSelect'],Instrument=dataset[0]['musics'][i]['set']["Instrument"])
|
||||
|
||||
|
||||
'''
|
||||
|
||||
27
src/musicreater/msctspt/threadOpera.py
Normal file
27
src/musicreater/msctspt/threadOpera.py
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
|
||||
import threading
|
||||
|
||||
|
||||
class NewThread(threading.Thread):
|
||||
'''新建一个进程来运行函数,函数运行完毕后可以使用.getResult方法获取其返回值'''
|
||||
def __init__(self, func, args=()):
|
||||
super(NewThread, self).__init__()
|
||||
self.func = func
|
||||
self.args = args
|
||||
def run(self):
|
||||
self.result = self.func(*self.args)
|
||||
def getResult(self):
|
||||
threading.Thread.join(self) # 等待线程执行完毕
|
||||
try:
|
||||
return self.result
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
#
|
||||
# ————————————————
|
||||
# 版权声明:上面的类NewThread修改自CSDN博主「星火燎愿」的原创文章中的内容,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
||||
# 原文链接:https://blog.csdn.net/xpt211314/article/details/109543014
|
||||
# ————————————————
|
||||
#
|
||||
308
src/musicreater/msctspt/transfer.py
Normal file
308
src/musicreater/msctspt/transfer.py
Normal file
@@ -0,0 +1,308 @@
|
||||
"""音·创 的转换工具库"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def hans2pinyin(hans,style=3):
|
||||
"""将汉字字符串转化为拼音字符串"""
|
||||
from pypinyin import lazy_pinyin
|
||||
result = lazy_pinyin(hans=hans,style=style)
|
||||
final = ''
|
||||
for i in result:
|
||||
final += i;
|
||||
return final
|
||||
|
||||
|
||||
|
||||
|
||||
def formCmdBlock(direction:list,command:str,particularValue:int,impluse:int,condition:bool=False,needRedstone:bool=True,tickDelay:int=0,customName:str='',lastOutput:str='',executeOnFirstTick:bool=False,trackOutput:bool=True):
|
||||
"""
|
||||
使用指定项目返回指定的指令方块格式字典
|
||||
:param block: {
|
||||
"direction": [x: int, y: int, z: int] #方块位置
|
||||
"block_name": str, #方块名称(无需指定,默认为command_block)
|
||||
"particular_value": int, #方块特殊值
|
||||
"impluse": int, #方块类型0脉冲 1循环 2连锁 unsigned_int32
|
||||
"command": str, #指令
|
||||
"customName": str, #悬浮字
|
||||
"lastOutput": str, #上次输出
|
||||
"tickdelay": int, #方块延时 int32
|
||||
"executeOnFirstTick": int, #执行第一个选项 1 bytes
|
||||
"trackOutput": int, #是否输出 1 bytes
|
||||
"conditional": int, #是否有条件 1 bytes
|
||||
"needRedstone": int #是否需要红石 1 bytes
|
||||
}
|
||||
:return: 指令方块字典结构
|
||||
"""
|
||||
return {"direction": direction,
|
||||
"block_name": "command_block",
|
||||
"particular_value": particularValue,
|
||||
"impluse": impluse,
|
||||
"command": command,
|
||||
"customName": customName,
|
||||
"lastOutput": lastOutput,
|
||||
"tickdelay": tickDelay,
|
||||
"executeOnFirstTick": executeOnFirstTick,
|
||||
"trackOutput": trackOutput,
|
||||
"conditional": condition,
|
||||
"needRedstone": needRedstone
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
def note2bdx(filePath:str,dire:list,Notes : list,ScoreboardName:str,Instrument:str, PlayerSelect:str='',isProsess:bool=False,height:int = 200) :
|
||||
'''使用方法同Note2Cmd
|
||||
:param 参数说明:
|
||||
filePath: 生成.bdx文件的位置
|
||||
dire: 指令方块在地图中生成的起始位置(相对位置)
|
||||
Notes: 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ] 格式存储的音符列表 例如Musicreater.py的(dataset[0]['musics'][NowMusic]['notes'])
|
||||
ScoreboardName: 用于执行的计分板名称
|
||||
Instrument: 播放的乐器
|
||||
PlayerSelect: 执行的玩家选择器
|
||||
isProsess: 是否显示进度条(会很卡)
|
||||
height: 生成结构的最高高度
|
||||
:return 返回一个BdxConverter类(实际上没研究过),同时在指定位置生成.bdx文件'''
|
||||
|
||||
|
||||
from musicreater.msctspt.transfer import formCmdBlock
|
||||
from musicreater.nmcsup.trans import Note2Cmd
|
||||
from musicreater.msctspt.bdxOpera_CP import BdxConverter
|
||||
cmd = Note2Cmd(Notes,ScoreboardName,Instrument, PlayerSelect,isProsess)
|
||||
cdl = []
|
||||
for i in cmd:
|
||||
try:
|
||||
if (i[:i.index('#')].replace(' ','') != '\n') and(i[:i.index('#')].replace(' ','') != ''):
|
||||
cdl.append(i[:i.index('#')])
|
||||
except:
|
||||
cdl.append(i)
|
||||
i = 0
|
||||
down = False
|
||||
blocks = [formCmdBlock(dire,cdl.pop(0),1,1)]
|
||||
dire[1]+=1;
|
||||
for j in cdl:
|
||||
if dire[1]+i > height:
|
||||
dire[0]+=1
|
||||
i=0
|
||||
down = not down
|
||||
if dire[1]+i == height :
|
||||
blocks.append(formCmdBlock([dire[0],dire[1]+i,dire[2]],j,5,2,False,False))
|
||||
else:
|
||||
if down:
|
||||
blocks.append(formCmdBlock([dire[0],dire[1]+i,dire[2]],j,0,2,False,False))
|
||||
else:
|
||||
blocks.append(formCmdBlock([dire[0],dire[1]+i,dire[2]],j,1,2,False,False))
|
||||
i+=1
|
||||
del i, cdl, down, cmd
|
||||
return BdxConverter(filePath,'Build by RyounMusicreater',blocks)
|
||||
|
||||
|
||||
|
||||
|
||||
def note2webs(Notes : list,Instrument:str, speed:float = 5.0, PlayerSelect:str='',isProsess:bool=False) :
|
||||
'''传入音符,在oaclhost:8080上建立websocket服务器以供我的世界connect/wssever指令连接
|
||||
:param 参数说明:
|
||||
Notes: 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ] 格式存储的音符列表 例如Musicreater.py的(dataset[0]['musics'][NowMusic]['notes'])
|
||||
Instrument: 播放的乐器
|
||||
speed: 用于控制播放速度,数值越大,播放速度越快,相当于把一秒变为几拍
|
||||
PlayerSelect: 执行的玩家选择器
|
||||
isProsess: 是否显示进度条
|
||||
:return None'''
|
||||
|
||||
import time
|
||||
import fcwslib
|
||||
import asyncio
|
||||
from musicreater.nmcsup.log import log
|
||||
from musicreater.nmcsup.vers import VER
|
||||
|
||||
async def run_server(websocket, path):
|
||||
log('服务器连接创建')
|
||||
await fcwslib.tellraw(websocket, '已连接服务器——音·创'+VER[1]+VER[0]+' 作者:金羿(W-YI)')
|
||||
if isProsess:
|
||||
length = len(Notes)
|
||||
j = 1;
|
||||
for i in range(len(Notes)):
|
||||
await fcwslib.send_command(websocket,'execute @a'+PlayerSelect+' ~ ~ ~ playsound '+Instrument+' @s ~ ~ ~ 1000 '+str(Notes[i][0])+' 1000')
|
||||
if isProsess:
|
||||
fcwslib.send_command(websocket,'execute @a'+PlayerSelect+' ~ ~ ~ title @s actionbar §e▶ 播放中: §a'+str(j)+'/'+str(length)+' || '+str(int(j/length*1000)/10))
|
||||
j+=1;
|
||||
time.sleep(Notes[i][1]/speed)
|
||||
|
||||
fcwslib.run_server(run_server)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import amulet
|
||||
from amulet.api.block import Block
|
||||
from amulet.utils.world_utils import block_coords_to_chunk_coords as bc2cc
|
||||
from amulet_nbt import TAG_String as ts
|
||||
from nmcsup.log import log
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def note2RSworld(world:str,startpos:list,notes:list,instrument:str,speed:float = 2.5,posadder:list = [1,0,0],baseblock:str = 'stone') -> bool:
|
||||
'''传入音符,生成以音符盒存储的红石音乐
|
||||
:param 参数说明:
|
||||
world: 地图文件的路径
|
||||
startpos: list[int,int,int] 开始生成的坐标
|
||||
notes: list[list[float,float]] 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ] 格式存储的音符列表 例如Musicreater.py的dataset[0]['musics'][NowMusic]['notes']
|
||||
instrument: 播放的乐器
|
||||
speed: 一拍占多少个中继器延迟(红石刻/rt)
|
||||
posadder: list[int,int,int] 坐标增加规律,即红石的延长时按照此增加规律增加坐标
|
||||
baseblock: 在中继器下垫着啥方块呢~
|
||||
:return 是否生成成功
|
||||
'''
|
||||
|
||||
|
||||
from musicreater.msctspt.values import height2note,instuments
|
||||
|
||||
|
||||
def formNoteBlock(note:int,instrument:str='note.harp',powered:bool = False):
|
||||
'''生成音符盒方块
|
||||
:param note: 0~24
|
||||
:return Block()'''
|
||||
if powered:
|
||||
powered = 'true';
|
||||
else:
|
||||
powered = 'false';
|
||||
return Block('universal_minecraft','noteblock',{"instrument":ts(instrument.replace("note.",'')),'note':ts(str(note)),'powered':ts(powered)})
|
||||
|
||||
def formRepeater(delay:int,facing:str,locked:bool=False,powered:bool=False):
|
||||
'''生成中继器方块
|
||||
:param delay: 1~4
|
||||
:return Block()'''
|
||||
if powered:powered = 'true';
|
||||
else:powered = 'false';
|
||||
if locked:locked = 'true';
|
||||
else:locked = 'false';
|
||||
return Block('universal_minecraft','repeater',{"delay":ts(str(delay)),'facing':ts(facing),'locked':ts(locked),'powered':ts(powered)})
|
||||
|
||||
|
||||
level = amulet.load_level(world)
|
||||
|
||||
def setblock(block:Block,pos:list):
|
||||
'''pos : list[int,int,int]'''
|
||||
cx, cz = bc2cc(pos[0], pos[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = pos[0] - 16 * cx, pos[2] - 16 * cz
|
||||
chunk.blocks[offset_x, pos[1], offset_z] = level.block_palette.get_add_block(block)
|
||||
chunk.changed = True
|
||||
|
||||
# 1拍 x 2.5 rt
|
||||
def placeNoteBlock():
|
||||
for i in notes:
|
||||
try :
|
||||
setblock(formNoteBlock(height2note[i[0]],instrument),[startpos[0],startpos[1]+1,startpos[2]])
|
||||
setblock(Block("universal_minecraft",instuments[i[0]][1]),startpos)
|
||||
except :
|
||||
log("无法放置音符:"+str(i)+'于'+str(startpos))
|
||||
setblock(Block("universal_minecraft",baseblock),startpos)
|
||||
setblock(Block("universal_minecraft",baseblock),[startpos[0],startpos[1]+1,startpos[2]])
|
||||
delay = int(i[1]*speed+0.5)
|
||||
if delay <= 4:
|
||||
startpos[0]+=1
|
||||
setblock(formRepeater(delay,'west'),[startpos[0],startpos[1]+1,startpos[2]])
|
||||
setblock(Block("universal_minecraft",baseblock),startpos)
|
||||
else:
|
||||
for i in range(int(delay/4)):
|
||||
startpos[0]+=1
|
||||
setblock(formRepeater(4,'west'),[startpos[0],startpos[1]+1,startpos[2]])
|
||||
setblock(Block("universal_minecraft",baseblock),startpos)
|
||||
if delay % 4 != 0:
|
||||
startpos[0]+=1
|
||||
setblock(formRepeater(delay%4,'west'),[startpos[0],startpos[1]+1,startpos[2]])
|
||||
setblock(Block("universal_minecraft",baseblock),startpos)
|
||||
startpos[0]+=posadder[0]
|
||||
startpos[1]+=posadder[1]
|
||||
startpos[2]+=posadder[2]
|
||||
try:
|
||||
placeNoteBlock()
|
||||
except:
|
||||
log("无法放置方块了,可能是因为区块未加载叭")
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ryStruct:
|
||||
|
||||
def __init__(self,world:str) -> None:
|
||||
|
||||
|
||||
self.RyStruct = dict()
|
||||
self._world = world
|
||||
self._level = amulet.load_level(world)
|
||||
|
||||
|
||||
def reloadLevel(self):
|
||||
try:
|
||||
self._level = amulet.load_level(self.world)
|
||||
except:
|
||||
log("无法重载地图")
|
||||
|
||||
def closeLevel(self):
|
||||
try:
|
||||
self._level.close()
|
||||
except:
|
||||
log("无法关闭地图")
|
||||
|
||||
|
||||
def world2Rys(self,startp:list,endp:list,includeAir:bool=False):
|
||||
'''将世界转换为RyStruct字典,注意,此函数运行成功后将关闭地图,若要打开需要运行 reloadLevel
|
||||
:param startp: [x,y,z] 转化的起始坐标
|
||||
:param endp : [x,y,z] 转换的终止坐标,注意,终止坐标需要大于起始坐标,且最终结果包含终止坐标
|
||||
:param includeAir : bool = False 是否包含空气,即空气是否在生成之时覆盖地图内容
|
||||
:return dict RyStruct '''
|
||||
|
||||
|
||||
level = self._level
|
||||
|
||||
|
||||
for x in range(startp[0],endp[0]+1):
|
||||
for y in range(startp[1],endp[1]+1):
|
||||
for z in range(startp[2],endp[2]+1):
|
||||
|
||||
RyStructBlock = dict()
|
||||
|
||||
cx, cz = bc2cc(x, z)
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
universal_block = chunk.block_palette[chunk.blocks[x - 16 * cx, y, z - 16 * cz]]
|
||||
if universal_block == Block("universal_minecraft","air") and includeAir:
|
||||
continue
|
||||
universal_block_entity = chunk.block_entities.get((x, y, z), None)
|
||||
|
||||
RyStructBlock["block"] = str(universal_block)
|
||||
RyStructBlock["blockEntity"] = str(universal_block_entity)
|
||||
|
||||
log("载入方块数据"+str(RyStructBlock))
|
||||
|
||||
self.RyStruct[(x,y,z)] = RyStructBlock
|
||||
|
||||
level.close()
|
||||
|
||||
return self.RyStruct
|
||||
|
||||
|
||||
|
||||
'''
|
||||
RyStruct = {
|
||||
(0,0,0) = {
|
||||
"block": str 完整的方块结构
|
||||
"blockEntity": str | 'None'
|
||||
}
|
||||
}
|
||||
'''
|
||||
59
src/musicreater/msctspt/values.py
Normal file
59
src/musicreater/msctspt/values.py
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
|
||||
instuments = {
|
||||
'note.banjo' : ['班卓琴','hay_block'],
|
||||
'note.bass' : ['贝斯','planks'],
|
||||
'note.bassattack' : ['低音鼓/贝斯','log'],
|
||||
'note.bd' : ['底鼓','stone'], #即basedrum
|
||||
'note.bell' : ['铃铛/钟琴','gold_block'],
|
||||
'note.bit' : ['比特/“芯片”(方波)','emerald_block'],
|
||||
'note.chime' : ['管钟','packed_ice'],
|
||||
'note.cow_bell' : ['牛铃','soul_sand'],
|
||||
'note.didgeridoo' : ['迪吉里杜管','pumpkin'],
|
||||
'note.flute' : ['长笛','clay'],
|
||||
'note.guitar' : ['吉他','wool'],
|
||||
'note.harp' : ['竖琴/钢琴','concrete'], #任意其他类型的方块皆可
|
||||
'note.hat' : ['击鼓沿/架子鼓','glass'],
|
||||
'note.iron_xylophone' : ['“铁木琴”(颤音琴)','iron_block'],
|
||||
'note.pling' : ['“扣弦”(电钢琴)','glowstone'],
|
||||
'note.snare' : ['小军鼓','sand'],
|
||||
'note.xylophone' : ['木琴','bone_block']
|
||||
}
|
||||
'''乐器对照表\n
|
||||
乐器英文:[中文, 对应音符盒下方块名称]
|
||||
注:方块仅取一个'''
|
||||
|
||||
|
||||
|
||||
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音高:音符盒音调'''
|
||||
|
||||
|
||||
72
src/musicreater/nmcsup/NFC Dev Log.txt
Normal file
72
src/musicreater/nmcsup/NFC Dev Log.txt
Normal file
@@ -0,0 +1,72 @@
|
||||
从此日志开始,我的世界函数音乐构建更名为 函数音创 NoteFunCreater(谐音NotFun[狗头]),版本号更为0.1.0开始
|
||||
|
||||
注意,运行此文件需要第三方库:
|
||||
1. mido 用于对midi文件的解码
|
||||
2. py7zr 用于对7z压缩包的压缩与解压等(需pycparser, cffi, texttable, pyzstd, pyppmd, pycryptodomex, multivolumefile, brotli, bcj-cffi支持) -(从0.1.3开始不需要)
|
||||
3. zipfile 用于自动生成函数包的压缩
|
||||
4. pystray 用于支持窗口任务栏
|
||||
5. pillow (相当于Python2的PIL)用于绘图
|
||||
|
||||
|
||||
0.1.0
|
||||
2021 7 10 - 2021 7 12
|
||||
1.程序窗口化
|
||||
2.仅支持基本的菜单操作
|
||||
3.程序文件皆储存至其相应目录下
|
||||
4.程序./bin/目录下文件将会自动防修改
|
||||
5.删除了彩蛋
|
||||
|
||||
|
||||
0.1.1
|
||||
2021 7 14
|
||||
1.新增版本辨别的提示
|
||||
2.窗口中显示歌曲信息
|
||||
|
||||
|
||||
0.1.2
|
||||
2021 7 14 - 2021 7 15
|
||||
1.在没运行过的机器上会自动安装库
|
||||
2.从midi导入时不会删除其他音轨
|
||||
3.改进UI样式
|
||||
4.支持对于单个音轨设置的修改以及音乐主设置的修改
|
||||
5.当未保存便退出时,会询问存储
|
||||
6.新增加载进度提示
|
||||
|
||||
|
||||
0.1.3
|
||||
2021 7 15 - 2021 7 19
|
||||
1.不再从文件中读取音符及乐器信息(所以包更小了)
|
||||
2.改进UI
|
||||
3.修复了修改玩家选择器时变更了音乐标题的bug
|
||||
4.新增删除当前选定音轨按钮
|
||||
5.新增重置设置按钮(将音乐总设置设置为开始时的设置)
|
||||
6.运用多线程加载函数与文件等,程序运行效率更高
|
||||
7.修复变量作用域混淆问题
|
||||
|
||||
|
||||
0.1.3.1
|
||||
2021 7 19
|
||||
1.修复了菜单中无法退出程序的问题
|
||||
|
||||
|
||||
0.1.4
|
||||
2021 7 22
|
||||
1.支持显示指令于列表中
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TO-DO
|
||||
1.支持从midi文件的元信息中收取音符信息并自动生成
|
||||
2.支持生成zip函数包
|
||||
3.支持使用WebSocket接口自动播放已编辑的音乐
|
||||
4.可以编辑多个项目
|
||||
5.能够自动将一个长串的音乐分成多个函数文件
|
||||
6.支持用户导入自己的乐器
|
||||
7.支持汇报崩溃记录(通过邮件附件的方式)
|
||||
8.支持播放字幕
|
||||
9.支持任务栏角标与通知
|
||||
10.将控制台版本的彩蛋移植到此版本,开启了任务栏
|
||||
11.可编辑音符
|
||||
36
src/musicreater/nmcsup/NMC Dev Log.txt
Normal file
36
src/musicreater/nmcsup/NMC Dev Log.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
世界音创(NoteMapCreater)是金羿开发的一款用于生成我的世界中各类有关音乐的物件的软件
|
||||
软件禁止商用,源代码始终公开,如使用未经授权的音乐经过此软件生成的任何物件侵犯了他人权利与本软件及其作者无关
|
||||
|
||||
Copyright © W-YI 2021
|
||||
|
||||
开头,特别感谢:
|
||||
KCINE:提供Cinemusicedit函数包(虽然函数包没怎么用过)
|
||||
Charlie_Ping:提供MusiCreaterBot(音乐地图生成QQ机器人)源码核心以及时不时的催更(虽然源码没有抄)
|
||||
金羿(作者本人):提供NoteFunCreater(函数音创)的制作经验以及时不时的摸鱼(虽然不是很支持函数音创)
|
||||
广大群友:高效的催更作业让我以蜗牛的速度前进
|
||||
|
||||
Alpha 0.0.0
|
||||
2021 8 1 - 2021 8 10
|
||||
1.确定了大概的功能
|
||||
2.不支持无参数传入
|
||||
3.可以查看帮助,但是帮助大多功能没实现
|
||||
4.可以从格式文本、midi文件、钢琴声音MP3导入音轨
|
||||
5.可以生成一些方块到世界里,但是没有播放器(半支持bw开关)
|
||||
5.提供了修改文件地址的方法,但是不能修改
|
||||
|
||||
Alpha 0.0.1
|
||||
2021 8 10
|
||||
1.可以从函数音创的工程文件读取音轨
|
||||
2.可以新建一个空白世界来生成
|
||||
3.支持修改输出文件地址
|
||||
4.支持修改输出方块起始位置
|
||||
5.支持指定播放乐器,执行实体,执行积分板,播放玩家选择器
|
||||
6.可以生成指令音乐地图(完全支持-w开关)
|
||||
|
||||
Beta 0.0.0
|
||||
2021 8 X?
|
||||
1.除了-nw 和 -f 开关不支持以外都支持了
|
||||
|
||||
Beta 0.0.1
|
||||
2021 8 19
|
||||
1.修复了大量bug
|
||||
0
src/musicreater/nmcsup/__init__.py
Normal file
0
src/musicreater/nmcsup/__init__.py
Normal file
320
src/musicreater/nmcsup/const.py
Normal file
320
src/musicreater/nmcsup/const.py
Normal file
@@ -0,0 +1,320 @@
|
||||
"""音创系列的音符对照表 以及一系列常数"""
|
||||
|
||||
|
||||
|
||||
notes = {
|
||||
'....A' : [0.074, 27.5, 'wood', 8],
|
||||
'....A#' : [0.0787, 29.135, 'wood', 9],
|
||||
'....B' : [0.083, 30.868, 'wood', 10],
|
||||
'...C' : [0.088, 32.703, 'wood', 11],
|
||||
'...C#' : [0.094, 34.648, 'wood', 12],
|
||||
'...D' : [0.1, 36.708, 'wood', 13],
|
||||
'...D#' : [0.105, 38.891, 'log', 0],
|
||||
'...E' : [0.11, 41.203, 'log', 1],
|
||||
'...F' : [0.12, 43.654, 'log', 2],
|
||||
'...F#' : [0.125, 46.249, 'wood', 0],
|
||||
'...G' : [0.13, 48.999, 'wood', 1],
|
||||
'...G#' : [0.14, 51.913, 'wood', 2],
|
||||
'...A' : [0.15, 55.0, 'wood', 3],
|
||||
'...A#' : [0.16, 58.27, 'wood', 4],
|
||||
'...B' : [0.17, 61.735, 'wood', 5],
|
||||
'..C' : [0.18, 65.406, 'wool', 0],
|
||||
'..C#' : [0.19, 69.296, 'wool', 1],
|
||||
'..D' : [0.2, 73.416, 'wool', 2],
|
||||
'..D#' : [0.21, 77.782, 'wool', 3],
|
||||
'..E' : [0.22, 82.407, 'wool', 4],
|
||||
'..F' : [0.235, 87.307, 'wool', 5],
|
||||
'..F#' : [0.25, 92.499, 'concretepowder', 0],
|
||||
'..G' : [0.26, 97.999, 'concretepowder', 1],
|
||||
'..G#' : [0.28, 103.826, 'concretepowder', 2],
|
||||
'..A' : [0.3, 110.0, 'concretepowder', 3],
|
||||
'..A#' : [0.31, 116.541, 'concretepowder', 4],
|
||||
'..B' : [0.33, 123.471, 'concretepowder', 5],
|
||||
'.C' : [0.35, 130.813, 'concretepowder', 6],
|
||||
'.C#' : [0.37, 138.591, 'concretepowder', 7],
|
||||
'.D' : [0.4, 146.832, 'concretepowder', 8],
|
||||
'.D#' : [0.42, 155.563, 'concretepowder', 9],
|
||||
'.E' : [0.44, 164.814, 'concretepowder', 10],
|
||||
'.F' : [0.47, 174.614, 'concretepowder', 11],
|
||||
'.F#' : [0.5, 184.997, 'concretepowder', 12],
|
||||
'.G' : [0.53, 195.998, 'concretepowder', 13],
|
||||
'.G#' : [0.56, 207.652, 'concretepowder', 14],
|
||||
'.A' : [0.6, 220.0, 'concretepowder', 15],
|
||||
'.A#' : [0.63, 233.082, 'concrete', 0],
|
||||
'.B' : [0.67, 246.942, 'concrete', 1],
|
||||
'C' : [0.7, 261.626, 'concrete', 2],
|
||||
'C#' : [0.75, 277.183, 'concrete', 3],
|
||||
'D' : [0.8, 293.665, 'concrete', 4],
|
||||
'D#' : [0.84, 311.127, 'concrete', 5],
|
||||
'E' : [0.9, 329.628, 'concrete', 6],
|
||||
'F' : [0.94, 349.228, 'concrete', 7],
|
||||
'F#' : [1.0, 369.994, 'concrete', 8],
|
||||
'G' : [1.05, 391.995, 'concrete', 9],
|
||||
'G#' : [1.12, 415.305, 'concrete', 10],
|
||||
'A' : [1.2, 440.0, 'concrete', 11],
|
||||
'A#' : [1.25, 466.164, 'concrete', 12],
|
||||
'B' : [1.33, 493.883, 'concrete', 13],
|
||||
'`C' : [1.4, 523.251, 'concrete', 14],
|
||||
'`C#' : [1.5, 554.365, 'concrete', 15],
|
||||
'`D' : [1.6, 587.33, 'stained_hardened_clay', 0],
|
||||
'`D#' : [1.7, 622.254, 'stained_hardened_clay', 1],
|
||||
'`E' : [1.8, 659.255, 'stained_hardened_clay', 2],
|
||||
'`F' : [1.9, 698.456, 'stained_hardened_clay', 3],
|
||||
'`F#' : [2.0, 739.989, 'stained_hardened_clay', 4],
|
||||
'`G' : [2.1, 783.991, 'stained_hardened_clay', 5],
|
||||
'`G#' : [2.24, 830.609, 'stained_hardened_clay', 6],
|
||||
'`A' : [2.4, 880.0, 'stained_hardened_clay', 7],
|
||||
'`A#' : [2.5, 932.328, 'stained_hardened_clay', 8],
|
||||
'`B' : [2.67, 987.767, 'stained_hardened_clay', 9],
|
||||
'``C' : [2.83, 1046.502, 'stained_hardened_clay', 10],
|
||||
'``C#' : [3.0, 1108.731, 'stained_hardened_clay', 11],
|
||||
'``D' : [3.17, 1174.659, 'stained_hardened_clay', 12],
|
||||
'``D#' : [3.36, 1244.508, 'stained_hardened_clay', 13],
|
||||
'``E' : [3.56, 1318.51, 'stained_hardened_clay', 14],
|
||||
'``F' : [3.78, 1396.913, 'stained_hardened_clay', 15],
|
||||
'``F#' : [4.0, 1479.978, 'white_glazed_terracotta', 0],
|
||||
'``G' : [4.24, 1567.982, 'orange_glazed_terracotta', 0],
|
||||
'``G#' : [4.5, 1661.219, 'magenta_glazed_terracotta', 0],
|
||||
'``A' : [4.76, 1760.0, 'light_blue_glazed_terracotta', 0],
|
||||
'``A#' : [5.04, 1864.655, 'yellow_glazed_terracotta', 0],
|
||||
'``B' : [5.34, 1975.533, 'lime_glazed_terracotta', 0],
|
||||
'```C' : [5.66, 2093.005, 'pink_glazed_terracotta', 0],
|
||||
'```C#' : [6.0, 2217.461, 'gray_glazed_terracotta', 0],
|
||||
'```D' : [6.35, 2349.318, 'silver_glazed_terracotta', 0],
|
||||
'```D#' : [6.73, 2489.016, 'cyan_glazed_terracotta', 0],
|
||||
'```E' : [7.13, 2637.02, 'purple_glazed_terracotta', 0],
|
||||
'```F' : [7.55, 2793.826, 'blue_glazed_terracotta', 0],
|
||||
'```F#' : [8.0, 2959.955, 'brown_glazed_terracotta', 0],
|
||||
'```G' : [8.47, 3135.963, 'green_glazed_terracotta', 0],
|
||||
'```G#' : [8.98, 3322.438, 'red_glazed_terracotta', 0],
|
||||
'```A' : [9.51, 3520.0, 'black_glazed_terracotta', 0],
|
||||
'```A#' : [10.08, 3729.31, 'stained_glass', 0],
|
||||
'```B' : [10.68, 3951.066, 'stained_glass', 1],
|
||||
'````C' : [11.31, 4186.009, 'stained_glass', 2],
|
||||
'0' : [0.0, 0.0, 'glass', 0]
|
||||
}
|
||||
'''音符对照表\n
|
||||
音符:[MC音调, 声音频率, 方块名称, 数据值]'''
|
||||
|
||||
|
||||
|
||||
|
||||
#方块
|
||||
'''
|
||||
blocks = {
|
||||
0.074 : ['stained_glass', 3],
|
||||
0.0787 : ['stained_glass', 4],
|
||||
0.083 : ['stained_glass', 5],
|
||||
0.088 : ['stained_glass', 6],
|
||||
0.094 : ['stained_glass', 7],
|
||||
0.1 : ['stained_glass', 8],
|
||||
0.105 : ['stained_glass', 9],
|
||||
0.11 : ['stained_glass', 10],
|
||||
0.12 : ['stained_glass', 11],
|
||||
0.125 : ['stained_glass', 12],
|
||||
0.13 : ['stained_glass', 13],
|
||||
0.14 : ['stained_glass', 14],
|
||||
0.15 : ['stained_glass', 15],
|
||||
0.16 : ['wool', 0],
|
||||
0.17 : ['wool', 1],
|
||||
0.18 : ['wool', 2],
|
||||
0.19 : ['wool', 3],
|
||||
0.2 : ['wool', 4],
|
||||
0.21 : ['wool', 5],
|
||||
0.22 : ['wool', 6],
|
||||
0.235 : ['wool', 7],
|
||||
0.25 : ['concretepowder', 0],
|
||||
0.26 : ['concretepowder', 1],
|
||||
0.28 : ['concretepowder', 2],
|
||||
0.3 : ['concretepowder', 3],
|
||||
0.31 : ['concretepowder', 4],
|
||||
0.33 : ['concretepowder', 5],
|
||||
0.35 : ['concretepowder', 6],
|
||||
0.37 : ['concretepowder', 7],
|
||||
0.4 : ['concretepowder', 8],
|
||||
0.42 : ['concretepowder', 9],
|
||||
0.44 : ['concretepowder', 10],
|
||||
0.47 : ['concretepowder', 11],
|
||||
0.5 : ['concretepowder', 12],
|
||||
0.53 : ['concretepowder', 13],
|
||||
0.56 : ['concretepowder', 14],
|
||||
0.6 : ['concretepowder', 15],
|
||||
0.63 : ['concrete', 0],
|
||||
0.67 : ['concrete', 1],
|
||||
0.7 : ['concrete', 2],
|
||||
0.75 : ['concrete', 3],
|
||||
0.8 : ['concrete', 4],
|
||||
0.84 : ['concrete', 5],
|
||||
0.9 : ['concrete', 6],
|
||||
0.94 : ['concrete', 7],
|
||||
1.0 : ['concrete', 8],
|
||||
1.05 : ['concrete', 9],
|
||||
1.12 : ['concrete', 10],
|
||||
1.2 : ['concrete', 11],
|
||||
1.25 : ['concrete', 12],
|
||||
1.33 : ['concrete', 13],
|
||||
1.4 : ['concrete', 14],
|
||||
1.5 : ['concrete', 15],
|
||||
1.6 : ['stained_hardened_clay', 0],
|
||||
1.7 : ['stained_hardened_clay', 1],
|
||||
1.8 : ['stained_hardened_clay', 2],
|
||||
1.9 : ['stained_hardened_clay', 3],
|
||||
2.0 : ['stained_hardened_clay', 4],
|
||||
2.1 : ['stained_hardened_clay', 5],
|
||||
2.24 : ['stained_hardened_clay', 6],
|
||||
2.4 : ['stained_hardened_clay', 7],
|
||||
2.5 : ['stained_hardened_clay', 8],
|
||||
2.67 : ['stained_hardened_clay', 9],
|
||||
2.83 : ['stained_hardened_clay', 10],
|
||||
3.0 : ['stained_hardened_clay', 11],
|
||||
3.17 : ['stained_hardened_clay', 12],
|
||||
3.36 : ['stained_hardened_clay', 13],
|
||||
3.56 : ['stained_hardened_clay', 14],
|
||||
3.78 : ['stained_hardened_clay', 15],
|
||||
4.0 : ['stained_glass_pane', 0],
|
||||
4.24 : ['stained_glass_pane', 1],
|
||||
4.5 : ['stained_glass_pane', 2],
|
||||
4.76 : ['stained_glass_pane', 3],
|
||||
5.04 : ['stained_glass_pane', 4],
|
||||
5.34 : ['stained_glass_pane', 5],
|
||||
5.66 : ['stained_glass_pane', 6],
|
||||
6.0 : ['stained_glass_pane', 7],
|
||||
6.35 : ['stained_glass_pane', 8],
|
||||
6.73 : ['stained_glass_pane', 9],
|
||||
7.13 : ['stained_glass_pane', 10],
|
||||
7.55 : ['stained_glass_pane', 11],
|
||||
8.0 : ['stained_glass_pane', 12],
|
||||
8.47 : ['stained_glass_pane', 13],
|
||||
8.98 : ['stained_glass_pane', 14],
|
||||
9.51 : ['stained_glass_pane', 15],
|
||||
10.08 : ['stained_glass', 0],
|
||||
10.68 : ['stained_glass', 1],
|
||||
11.31 : ['stained_glass', 2],
|
||||
0.0 : ['glass', 0]
|
||||
}
|
||||
#向查理平致敬!!!!!
|
||||
'''
|
||||
|
||||
|
||||
Blocks = {
|
||||
0.074: 'barrel',
|
||||
0.0787: 'beacon',
|
||||
0.083: 'bedrock',
|
||||
0.088: 'black_glazed_terracotta',
|
||||
0.094: 'blast_furnace',
|
||||
0.1: 'blue_glazed_terracotta',
|
||||
0.105: 'blue_ice',
|
||||
0.11: 'bone_block',
|
||||
0.12: 'bookshelf',
|
||||
0.125: 'brick_block',
|
||||
0.13: 'brown_glazed_terracotta',
|
||||
0.14: 'cartography_table',
|
||||
0.15: 'carved_pumpkin',
|
||||
0.16: 'clay',
|
||||
0.17: 'coal_block',
|
||||
0.18: 'coal_ore',
|
||||
0.19: 'cobblestone',
|
||||
0.2: 'concrete',
|
||||
0.21: 'crafting_table',
|
||||
0.22: 'cyan_glazed_terracotta',
|
||||
0.235: 'diamond_block',
|
||||
0.25: 'diamond_ore',
|
||||
0.26: 'white_glazed_terracotta',
|
||||
0.28: 'dispenser',
|
||||
0.3: 'dried_kelp_block',
|
||||
0.31: 'dropper',
|
||||
0.33: 'emerald_block',
|
||||
0.35: 'emerald_ore',
|
||||
0.37: 'end_bricks',
|
||||
0.4: 'end_stone',
|
||||
0.42: 'fletching_table',
|
||||
0.44: 'furnace',
|
||||
0.47: 'glass',
|
||||
0.5: 'glowingobsidian',
|
||||
0.53: 'glowstone',
|
||||
0.56: 'gold_block',
|
||||
0.6: 'gold_ore',
|
||||
0.63: 'grass',
|
||||
0.67: 'gray_glazed_terracotta',
|
||||
0.7: 'green_glazed_terracotta',
|
||||
0.75: 'hardened_clay',
|
||||
0.8: 'hay_block',
|
||||
0.84: 'iron_block',
|
||||
0.9: 'iron_ore',
|
||||
0.94: 'jukebox',
|
||||
1.0: 'lapis_block',
|
||||
1.05: 'lapis_ore',
|
||||
1.12: 'light_blue_glazed_terracotta',
|
||||
1.2: 'lime_glazed_terracotta',
|
||||
1.25: 'lit_pumpkin',
|
||||
1.33: 'log',
|
||||
1.4: 'loom',
|
||||
1.5: 'magenta_glazed_terracotta',
|
||||
1.6: 'magma',
|
||||
1.7: 'melon_block',
|
||||
1.8: 'web',
|
||||
1.9: 'mossy_cobblestone',
|
||||
2.0: 'nether_brick',
|
||||
2.1: 'nether_wart_block',
|
||||
2.24: 'netherrack',
|
||||
2.4: 'noteblock',
|
||||
2.5: 'observer',
|
||||
2.67: 'obsidian',
|
||||
2.83: 'orange_glazed_terracotta',
|
||||
3.0: 'pink_glazed_terracotta',
|
||||
3.17: 'piston',
|
||||
3.36: 'planks',
|
||||
3.56: 'prismarine',
|
||||
3.78: 'pumpkin',
|
||||
4.0: 'purple_glazed_terracotta',
|
||||
4.24: 'purpur_block',
|
||||
4.5: 'quartz_block',
|
||||
4.76: 'quartz_ore',
|
||||
5.04: 'red_glazed_terracotta',
|
||||
5.34: 'red_nether_brick',
|
||||
5.66: 'red_sandstone',
|
||||
6.0: 'redstone_block',
|
||||
6.35: 'yellow_glazed_terracotta',
|
||||
6.73: 'sandstone',
|
||||
7.13: 'stonebrick',
|
||||
7.55: 'silver_glazed_terracotta',
|
||||
8.0: 'slime',
|
||||
8.47: 'smithing_table',
|
||||
8.98: 'smoker',
|
||||
9.51: 'smooth_stone',
|
||||
10.08: 'snow',
|
||||
10.68: 'soul_sand',
|
||||
11.31: 'sponge',
|
||||
0.0: 'stone'
|
||||
}
|
||||
'''频率对照表\n
|
||||
MC音调:方块名称'''
|
||||
|
||||
|
||||
|
||||
# 乐器
|
||||
Instuments = {
|
||||
'note.banjo' : '班卓',
|
||||
'note.bass' : '低音',
|
||||
'note.bassattack' : '贝斯',
|
||||
'note.bd' : '鼓声',
|
||||
'note.bell' : '铃声',
|
||||
'note.bit' : '比特',
|
||||
'note.cow_bell' : '牛铃',
|
||||
'note.didgeridoo' : '迪吉',
|
||||
'note.flute' : '长笛',
|
||||
'note.guitar' : '吉他',
|
||||
'note.harp' : '竖琴',
|
||||
'note.hat' : '架鼓',
|
||||
'note.chime' : '钟声',
|
||||
'note.iron_xylophone' : '铁琴',
|
||||
'note.pling' : '叮叮',
|
||||
'note.snare' : '响弦',
|
||||
'note.xylophone' : '木琴'
|
||||
}
|
||||
'''乐器对照表\n
|
||||
乐器英文:中文
|
||||
翻译:雪莹工坊Fun-Fer'''
|
||||
|
||||
|
||||
|
||||
17
src/musicreater/nmcsup/log.py
Normal file
17
src/musicreater/nmcsup/log.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""提供对于音创系列的日志"""
|
||||
|
||||
import datetime,os
|
||||
|
||||
#载入日志功能
|
||||
StrStartTime = str(datetime.datetime.now()).replace(':', '_')[:-7]
|
||||
'''字符串型的程序开始时间'''
|
||||
|
||||
|
||||
def log(info:str = '',isPrinted:bool = True):
|
||||
'''将信息连同当前时间载入日志'''
|
||||
if not os.path.exists('./log/'):
|
||||
os.makedirs('./log/')
|
||||
with open('./log/'+StrStartTime+'.msct.log', 'a',encoding='UTF-8') as f:
|
||||
f.write(str(datetime.datetime.now())[11:19]+' '+info+'\n')
|
||||
if isPrinted:
|
||||
print(str(datetime.datetime.now())[11:19]+' '+info)
|
||||
87
src/musicreater/nmcsup/nmcreader.py
Normal file
87
src/musicreater/nmcsup/nmcreader.py
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
"""音创系列的文件读取功能"""
|
||||
|
||||
|
||||
|
||||
|
||||
from musicreater.nmcsup.log import log
|
||||
from musicreater.nmcsup.const import notes
|
||||
|
||||
|
||||
|
||||
#从格式文本文件读入一个音轨并存入一个列表
|
||||
def ReadFile(fn : str) -> list:
|
||||
from musicreater.nmcsup.trans import note2list
|
||||
log('打开'+fn+"并读取音符")
|
||||
try:
|
||||
nat = open(fn, 'r', encoding='UTF-8').read().split(" ")
|
||||
del fn
|
||||
except:
|
||||
log("找不到读取目标文件")
|
||||
return False
|
||||
Notes = []
|
||||
log(str(nat)+"已读取")
|
||||
for i in range(int(len(nat)/2)):
|
||||
Notes.append([nat[i*2], float(nat[i*2+1])])
|
||||
Notes = note2list(Notes)
|
||||
log('音符数据更新'+str(Notes))
|
||||
return [Notes,]
|
||||
|
||||
|
||||
#从midi读入多个音轨,返回多个音轨列表
|
||||
def ReadMidi(midfile : str ) -> list:
|
||||
import mido
|
||||
from musicreater.msctspt.threadOpera import NewThread
|
||||
Notes = []
|
||||
try:
|
||||
mid = mido.MidiFile(midfile)
|
||||
except:
|
||||
log("找不到文件或无法读取文件"+midfile)
|
||||
return False
|
||||
# 解析
|
||||
ks = list(notes.values())
|
||||
def loadMidi(track):
|
||||
datas = []
|
||||
for i in track:
|
||||
if i.is_meta:
|
||||
log('元信息'+str(i))
|
||||
pass # 不处理元信息
|
||||
elif 'note_on' in str(i):
|
||||
msg = str(i).replace("note=", '').replace("time=", '').split(" ")
|
||||
log('音符on消息,处理后:'+str(msg))
|
||||
if msg[4] == '0':
|
||||
datas.append([ks[int(msg[2])-20][0], 1.0])
|
||||
log('延续时间0tick--:添加音符'+str([ks[int(msg[2])-20][0], 1.0]))
|
||||
else:
|
||||
datas.append([ks[int(msg[2])-20][0], float(msg[4])/480])
|
||||
log('延续时间'+msg[4]+'tick--:添加音符' +str([ks[int(msg[2])-20][0], float(msg[4])/480]))
|
||||
del msg
|
||||
log('音符增加'+str(datas))
|
||||
return datas
|
||||
for j, track in enumerate(mid.tracks):
|
||||
th = NewThread(loadMidi,(track,))
|
||||
th.start()
|
||||
Notes.append(th.getResult())
|
||||
del ks
|
||||
return Notes
|
||||
|
||||
|
||||
|
||||
|
||||
def ReadOldProject(fn:str) -> list:
|
||||
import json
|
||||
from musicreater.nmcsup.trans import note2list
|
||||
log("读取文件:"+fn)
|
||||
try:
|
||||
with open(fn, 'r', encoding='UTF-8') as c:
|
||||
dataset = json.load(c)
|
||||
except:
|
||||
print('找不到文件:'+fn+",请查看您是否输入正确")
|
||||
log("丢失"+fn)
|
||||
return False
|
||||
for i in range(len(dataset['musics'])):
|
||||
dataset['musics'][i]['notes'] = note2list(dataset['musics'][i]['notes'])
|
||||
#返回 音轨列表 选择器
|
||||
return dataset
|
||||
|
||||
|
||||
254
src/musicreater/nmcsup/trans.py
Normal file
254
src/musicreater/nmcsup/trans.py
Normal file
@@ -0,0 +1,254 @@
|
||||
|
||||
"""音创系列的转换功能"""
|
||||
|
||||
|
||||
|
||||
from nmcsup.log import log
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 输入一个列表 [ [str, float ], [], ... ] 音符str 值为持续时间float
|
||||
def note2list(Notes : list) -> list:
|
||||
from musicreater.nmcsup.const import notes
|
||||
def change(base):
|
||||
enwo = {
|
||||
'a': 'A',
|
||||
'b': 'B',
|
||||
'c': 'C',
|
||||
'd': "D",
|
||||
"e": "E",
|
||||
'f': 'F',
|
||||
'g': "G"
|
||||
}
|
||||
nuwo = {
|
||||
'6': 'A',
|
||||
'7': 'B',
|
||||
'1': 'C',
|
||||
'2': "D",
|
||||
"3": "E",
|
||||
'4': 'F',
|
||||
'5': "G"
|
||||
}
|
||||
for k, v in enwo.items():
|
||||
if k in base:
|
||||
base = base.replace(k, v)
|
||||
for k, v in nuwo.items():
|
||||
if k in base:
|
||||
base = base.replace(k, v)
|
||||
return base
|
||||
res = []
|
||||
log(" === 音符列表=>音调列表")
|
||||
for i in Notes:
|
||||
s2 = change(i[0])
|
||||
log(' === 正在操作音符'+i[0]+'->'+s2)
|
||||
if s2 in notes.keys():
|
||||
log(" === 找到此音符,加入:"+str(notes[s2][0]))
|
||||
res.append([notes[s2][0], float(i[1])])
|
||||
else:
|
||||
log(' === '+s2+'不在音符表内,此处自动替换为 休止符0 ')
|
||||
res.append(['0', float(i[1])])
|
||||
log(' === 最终反回'+str(res))
|
||||
return res
|
||||
|
||||
|
||||
|
||||
|
||||
def mcnote2freq(Notes):
|
||||
from musicreater.nmcsup.const import notes
|
||||
mcnback = {}
|
||||
for i,j in notes.items():
|
||||
mcnback[j[0]] = i
|
||||
res = []
|
||||
log(" === 我的世界音调表=>频率列表")
|
||||
for i in Notes:
|
||||
log(' === 正在操作音符'+i[0]+'->'+mcnback[i[0]])
|
||||
res.append([notes[mcnback[i[0]]][1], float(i[1])])
|
||||
log(' === 最终反回'+str(res))
|
||||
return res
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#MP3文件转midi文件
|
||||
def Mp32Mid(mp3File, midFile):
|
||||
from piano_transcription_inference import PianoTranscription, sample_rate, load_audio
|
||||
# 加载
|
||||
(audio, _) = load_audio(mp3File, sr=sample_rate, mono=True)
|
||||
# 实例化并转换
|
||||
PianoTranscription(device="cpu").transcribe(audio, midFile)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#传入一个音符列表转为指令列表
|
||||
def Note2Cmd(Notes : list,ScoreboardName:str,Instrument:str, PlayerSelect:str='',isProsess:bool=False) -> list:
|
||||
commands = []
|
||||
a = 0.0
|
||||
if isProsess:
|
||||
length = len(Notes)
|
||||
j = 1
|
||||
for i in range(len(Notes)):
|
||||
commands.append("execute @a"+PlayerSelect+" ~ ~ ~ execute @s[scores={"+ScoreboardName+"="+str(int((a+2)*5+int(Notes[i][1]*5)))+"}] ~ ~ ~ playsound "+Instrument+" @s ~ ~ ~ 1000 "+str(Notes[i][0])+" 1000\n")
|
||||
a += Notes[i][1]
|
||||
if isProsess:
|
||||
commands.append("execute @a"+PlayerSelect+" ~ ~ ~ execute @s[scores={"+ScoreboardName+"="+str(int((a+2)*5+int(Notes[i][1]*5)))+"}] ~ ~ ~ title @s actionbar §e▶ 播放中: §a"+str(j)+"/"+str(length)+" || "+str(int(j/length*1000)/10)+"\n")
|
||||
j+=1
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
return commands
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import amulet
|
||||
import amulet_nbt
|
||||
from amulet.api.block import Block
|
||||
from amulet.api.block_entity import BlockEntity
|
||||
from amulet.utils.world_utils import block_coords_to_chunk_coords
|
||||
from amulet_nbt import TAG_String,TAG_Compound,TAG_Byte
|
||||
|
||||
|
||||
|
||||
#简单载入方块
|
||||
#level.set_version_block(posx,posy,posz,"minecraft:overworld",("bedrock", (1, 16, 20)),Block(namespace, name))
|
||||
|
||||
|
||||
|
||||
#转入指令列表与位置信息转至世界
|
||||
def Cmd2World(cmd:list,world:str,dire:list):
|
||||
'''将指令以命令链的形式载入世界\n
|
||||
cmd指令列表位为一个序列,中包含指令字符串\n
|
||||
world为地图所在位置,需要指向文件夹,dire为指令方块生成之位置'''
|
||||
level = amulet.load_level(world)
|
||||
cdl = []
|
||||
for i in cmd:
|
||||
try:
|
||||
if (i[:i.index('#')].replace(' ','') != '\n') and(i[:i.index('#')].replace(' ','') != ''):
|
||||
cdl.append(i[:i.index('#')])
|
||||
except:
|
||||
cdl.append(i)
|
||||
i = 0
|
||||
#第一个是特殊
|
||||
universal_block = Block('universal_minecraft','command_block',{'conditional':TAG_String("false"),'facing':TAG_String('up'),'mode':TAG_String("repeating")})
|
||||
cx, cz = block_coords_to_chunk_coords(dire[0], dire[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = dire[0] - 16 * cx, dire[2] - 16 * cz
|
||||
universal_block_entity = BlockEntity( 'universal_minecraft','command_block',dire[0],dire[1],dire[2],amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound({'auto': TAG_Byte(0),'Command': TAG_String(cdl.pop(0))}) })))
|
||||
chunk.blocks[offset_x, dire[1], offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], dire[1], dire[2])] = universal_block_entity
|
||||
chunk.changed = True
|
||||
#集体上移
|
||||
dire[1]+=1;
|
||||
#真正开始
|
||||
down = False
|
||||
for j in cdl:
|
||||
if dire[1]+i >= 255:
|
||||
dire[0]+=1
|
||||
i=0
|
||||
down = not down
|
||||
#定义此方块
|
||||
if dire[1]+i == 254 :
|
||||
universal_block = Block('universal_minecraft','command_block',{'conditional':TAG_String("false"),'facing':TAG_String('east'),'mode':TAG_String("chain")})
|
||||
else:
|
||||
if down:
|
||||
universal_block = Block('universal_minecraft','command_block',{'conditional':TAG_String("false"),'facing':TAG_String('down'),'mode':TAG_String("chain")})
|
||||
else:
|
||||
universal_block = Block('universal_minecraft','command_block',{'conditional':TAG_String("false"),'facing':TAG_String('up'),'mode':TAG_String("chain")})
|
||||
cx, cz = block_coords_to_chunk_coords(dire[0], dire[2])
|
||||
#获取区块
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = dire[0] - 16 * cx, dire[2] - 16 * cz
|
||||
if down:
|
||||
#定义方块实体
|
||||
universal_block_entity = BlockEntity( 'universal_minecraft','command_block',dire[0],254-i,dire[2],amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound({'auto': TAG_Byte(1),'Command': TAG_String(j)}) })))
|
||||
|
||||
#将方块加入世界
|
||||
chunk.blocks[offset_x, 254-i, offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], 254-i, dire[2])] = universal_block_entity
|
||||
else:
|
||||
#定义方块实体
|
||||
universal_block_entity = BlockEntity( 'universal_minecraft','command_block',dire[0],dire[1]+i,dire[2],amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound({'auto': TAG_Byte(1),'Command': TAG_String(j)}) })))
|
||||
|
||||
#将方块加入世界
|
||||
chunk.blocks[offset_x, dire[1]+i, offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], dire[1]+i, dire[2])] = universal_block_entity
|
||||
#设置为已更新区块
|
||||
chunk.changed = True
|
||||
i+=1
|
||||
del i, cdl
|
||||
#保存世界并退出
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#音符转成方块再加载到世界里头
|
||||
def Blocks2World(world:str,dire:list,Datas:list):
|
||||
from musicreater.nmcsup.const import Blocks
|
||||
level = amulet.load_level(world)
|
||||
i = 0
|
||||
def setblock(block:str,pos:list):
|
||||
'''pos : list[int,int,int]'''
|
||||
cx, cz = block_coords_to_chunk_coords(pos[0], pos[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = pos[0] - 16 * cx, pos[2] - 16 * cz
|
||||
chunk.blocks[offset_x, pos[1], offset_z] = level.block_palette.get_add_block(Block("minecraft",block))
|
||||
chunk.changed = True
|
||||
for j in Datas:
|
||||
if dire[1]+1 >= 255:
|
||||
i = 0
|
||||
dire[0]+=1
|
||||
setblock(Blocks[j[0]],[dire[0],dire[1]+i,dire[2]])
|
||||
i = int(i+j[1]+0.5) #四舍五入
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#传入音符列表制作播放器指令
|
||||
def Notes2Player(Note,dire:list,CmdData:dict):
|
||||
'''传入音符列表、坐标、指令数据,生成播放器指令'''
|
||||
Notes = {}
|
||||
for i in Note:
|
||||
Notes[i[0]] = ''
|
||||
Notes = list(Notes.keys())
|
||||
from musicreater.nmcsup.const import Blocks
|
||||
Cmds = []
|
||||
for j in Notes:
|
||||
Cmds.append('execute @e[x='+str(dire[0])+',y='+str(dire[1])+',z='+str(dire[2])+',dy='+str(255-dire[1])+',name='+CmdData['Ent']+'] ~ ~ ~ detect ~ ~ ~ '+Blocks[j]+' 0 execute @a '+CmdData['Pls']+' ~ ~ ~ playsound '+CmdData['Ins']+' @s ~ ~ ~ 1000 '+str(j)+' 1000\n')
|
||||
Cmds+=['#本函数由 金羿 音·创 生成\n','execute @e[y='+str(dire[1])+',dy='+str(255-dire[1])+',name='+CmdData['Ent']+'] ~ ~ ~ tp ~ ~1 ~\n','execute @e[y=255,dy=100,name='+CmdData['Ent']+'] ~ ~ ~ tp ~1 '+str(dire[1])+' ~\n','#音·创 开发交流群 861684859']
|
||||
return Cmds
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#传入音符列表生成方块至世界
|
||||
def Datas2BlkWorld(NoteData,world:str,dire:list):
|
||||
for i in range(len(NoteData)):
|
||||
Blocks2World(world,[dire[0],dire[1],dire[2]+i],NoteData[i])
|
||||
|
||||
|
||||
89
src/musicreater/nmcsup/vers.py
Normal file
89
src/musicreater/nmcsup/vers.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""音创系列版本号和版本操作函数"""
|
||||
|
||||
|
||||
|
||||
from musicreater.msctspt.bugReporter import version
|
||||
|
||||
|
||||
#以下下两个值请在 msctspt/bugReporter 的version类中修改
|
||||
VER = version.version
|
||||
'''当前版本'''
|
||||
|
||||
LIBS = version.libraries
|
||||
'''当前所需库'''
|
||||
|
||||
|
||||
|
||||
#判断版本、临时文件与补全库
|
||||
def compver(ver1, ver2):
|
||||
"""
|
||||
传入不带英文的版本号,特殊情况:"10.12.2.6.5">"10.12.2.6"
|
||||
:param ver1: 版本号1
|
||||
:param ver2: 版本号2
|
||||
:return: ver1< = >ver2返回-1/0/1
|
||||
"""
|
||||
list1 = str(ver1).split(".")
|
||||
list2 = str(ver2).split(".")
|
||||
# 循环次数为短的列表的len
|
||||
for i in range(len(list1)) if len(list1) < len(list2) else range(len(list2)):
|
||||
if int(list1[i]) == int(list2[i]):
|
||||
pass
|
||||
elif int(list1[i]) < int(list2[i]):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
# 循环结束,哪个列表长哪个版本号高
|
||||
if len(list1) == len(list2):
|
||||
return 0
|
||||
elif len(list1) < len(list2):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
#
|
||||
# ————————————————
|
||||
# 版权声明:上面的函数compver为CSDN博主「基友死得早」的原创文章中的函数,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
||||
# 原文链接:https://blog.csdn.net/tinyjm/article/details/93514261
|
||||
# ————————————————
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
def InstallLibs(now,LIBS):
|
||||
'''比对库信息并安装库'''
|
||||
from os import system as run
|
||||
for i in LIBS:
|
||||
if not i in now:
|
||||
print("安装库:"+i)
|
||||
run("python -m pip install "+i+" -i https://pypi.tuna.tsinghua.edu.cn/simple")
|
||||
|
||||
|
||||
def chkver(ver = VER,libs = LIBS):
|
||||
'''通过文件比对版本信息并安装库'''
|
||||
if not os.path.exists(os.getenv('APPDATA')+'\\Musicreater\\msct.ActiveDatas.msct'):
|
||||
print("新安装库")
|
||||
os.makedirs(os.getenv('APPDATA')+'\\Musicreater\\')
|
||||
with open(os.getenv('APPDATA')+'\\Musicreater\\msct.ActiveDatas.msct', 'w') as f:
|
||||
f.write(ver[0]+'\n')
|
||||
for i in libs:
|
||||
f.write(i+'\n')
|
||||
InstallLibs([],libs)
|
||||
else:
|
||||
with open(os.getenv('APPDATA')+'\\Musicreater\\msct.ActiveDatas.msct', 'r') as f:
|
||||
v = f.readlines()
|
||||
cp = compver(ver[0], v[0])
|
||||
if cp != 0:
|
||||
InstallLibs(v[1:],libs)
|
||||
with open(os.getenv('APPDATA')+'\\Musicreater\\msct.ActiveDatas.msct', 'w') as f:
|
||||
f.write(ver[0]+'\n')
|
||||
for i in libs:
|
||||
f.write(i+'\n')
|
||||
del cp
|
||||
|
||||
|
||||
def resetver():
|
||||
'''重置版本信息'''
|
||||
import shutil
|
||||
shutil.rmtree(os.getenv('APPDATA')+'\\Musicreater\\')
|
||||
|
||||
|
||||
|
||||
11
src/musicreater/resources/ChineseLang.py
Normal file
11
src/musicreater/resources/ChineseLang.py
Normal file
@@ -0,0 +1,11 @@
|
||||
LANGUAGE = {
|
||||
'main':{
|
||||
"name":"音·创",
|
||||
"version":"当前版本",
|
||||
"run":"执行指令",
|
||||
},
|
||||
'command':{
|
||||
"NotAvailable":"此指令不可用。",
|
||||
"FormatError":"指令格式错误,请查看 命令行操作.md 以查阅指令。"
|
||||
}
|
||||
}
|
||||
BIN
src/musicreater/resources/EptWorld.zip
Normal file
BIN
src/musicreater/resources/EptWorld.zip
Normal file
Binary file not shown.
0
src/musicreater/resources/__init__.py
Normal file
0
src/musicreater/resources/__init__.py
Normal file
BIN
src/musicreater/resources/musicreater.icns
Normal file
BIN
src/musicreater/resources/musicreater.icns
Normal file
Binary file not shown.
BIN
src/musicreater/resources/musicreater.ico
Normal file
BIN
src/musicreater/resources/musicreater.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
src/musicreater/resources/musicreater.png
Normal file
BIN
src/musicreater/resources/musicreater.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 441 KiB |
11
src/musicreater/resources/mySayings.txt
Normal file
11
src/musicreater/resources/mySayings.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
生命灵动 当用激情跃起奋发之力
|
||||
奇偶数阵
|
||||
学海无涯 应用爱意徜徉
|
||||
在生命的起源寻找灵魂的慰藉
|
||||
纪念那一段辉煌灿烂的青春年华
|
||||
以梦想为驱使 创造属于自己的未来
|
||||
集青春之力 绽放爱意之花
|
||||
那个曾与我相伴的人 依稀在我的心头留恋
|
||||
我爱你 我 爱 你
|
||||
你是我灵魂中绽放出最艳丽的花朵
|
||||
心之所向 意之所属
|
||||
@@ -1,3 +0,0 @@
|
||||
python -m build
|
||||
python -m twine upload dist/*
|
||||
python clean_update.py
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
python -m build
|
||||
python -m twine upload dist/*
|
||||
python clean_update.py
|
||||
@@ -1,3 +0,0 @@
|
||||
python setup.py sdist bdist_wheel
|
||||
python -m twine upload dist/*
|
||||
python clean_update.py
|
||||
34
命令行操作.md
Normal file
34
命令行操作.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Musicreater 音·创 命令行模式
|
||||
|
||||
为了对后期安卓的兼容,先支持命令行
|
||||
|
||||
## 命令列表
|
||||
|
||||
### exit \[/s\] \[/c\]
|
||||
|
||||
- ```/s``` 保存并退出
|
||||
- ```/c``` 清除日志
|
||||
|
||||
### save \[/a \<fileName\>\]
|
||||
|
||||
- ```/a <文件名>``` 指定文件名保存
|
||||
|
||||
### load \[/\<loadMethod: input|txt|mid\> \<text|fileName\>\]
|
||||
|
||||
- ```/input <文本>``` 输入音符
|
||||
- ```/txt <文件名>``` 从文本载入音符
|
||||
- ```/mid <文件名>``` 解析midi文件载入音符
|
||||
|
||||
### win
|
||||
|
||||
- 开启窗口模式的 音·创(仅支持的系统下有效)
|
||||
|
||||
### chdir \<direction\>
|
||||
|
||||
- 切换当前工作目录
|
||||
|
||||
### build \[/\<buildMethod: file|directory|mcpack\> \<direction\>\]
|
||||
|
||||
- ```/file <目录位置>``` 在指定目录生成函数文件(散装)
|
||||
- ```/directory <目录位置>``` 在指定目录生成一个附加包目录
|
||||
- ```/mcpack <目录位置>``` 在指定目录生成一个.mcpack附加包
|
||||
29
查看代码数.py
Normal file
29
查看代码数.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- conding: utf8 -*-
|
||||
|
||||
import os
|
||||
from src.musicreater.msctspt.funcOpera import keepart
|
||||
|
||||
|
||||
l = 0
|
||||
|
||||
|
||||
|
||||
for path,dir_list,file_list in os.walk(r"./") :
|
||||
for file_name in file_list:
|
||||
if keepart(file_name,'.',None) == '.py':
|
||||
file = os.path.join(path, file_name)
|
||||
print("得到文件名:"+str(file))
|
||||
for i in open(file,'r',encoding="utf-8"):
|
||||
code = i.replace(' ','').replace('\n','')
|
||||
try:
|
||||
code -= code[code.index('#'):]
|
||||
except:
|
||||
pass;
|
||||
if code:
|
||||
print("\t"+code)
|
||||
l+=1
|
||||
else:
|
||||
pass;
|
||||
|
||||
input("\n最终代码行数为:"+str(l))
|
||||
|
||||
224
测试用/RyounTeamSong.ry.nfc
Normal file
224
测试用/RyounTeamSong.ry.nfc
Normal file
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"mainset": {
|
||||
"PackName": "RyounTeamSong",
|
||||
"MusicTitle": "RyounUp",
|
||||
"IsRepeat": false,
|
||||
"PlayerSelect": ""
|
||||
},
|
||||
"musics": [
|
||||
{
|
||||
"set": {
|
||||
"EntityName": "MusicSupport",
|
||||
"ScoreboardName": "MusicSupport",
|
||||
"Instrument": "harp",
|
||||
"FileName": "RyounUp_RyounTeamSong"
|
||||
},
|
||||
"notes": [
|
||||
[
|
||||
".5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.5
|
||||
],
|
||||
[
|
||||
"3",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.5
|
||||
],
|
||||
[
|
||||
"1",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
".6",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
".5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"6",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"5",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"3",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"2",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"0",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
".5",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
".6",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"6",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"3",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"2",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"5",
|
||||
1.5
|
||||
],
|
||||
[
|
||||
".5",
|
||||
0.5
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"1",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"0",
|
||||
1.0
|
||||
],
|
||||
[
|
||||
"0",
|
||||
1.0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
测试用/义勇军进行曲.mid
Normal file
BIN
测试用/义勇军进行曲.mid
Normal file
Binary file not shown.
1
测试用/义勇军进行曲.msct
Normal file
1
测试用/义勇军进行曲.msct
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user