|
13 | 13 | - IR在代码中就是`Chart`类,以及它所引用的`Note`、`BPMList`等子类。 |
14 | 14 | - 然而,对MA2和Simai稍有了解的朋友们都知道,**它们二者的表达能力是不等价的**。(严格说来Simai的表达能力更强,但MA2也有一些独特的、没法简单的等价到Simai语法中的设计) |
15 | 15 | - 最简单的一点是,MA2的所有音符都是对齐到Tick,即1/384小节的。你无法把类似`{36}1,1,1,1,`这样的、使用了无法被384整除的分音的Simai,转化为完全等价、不丢失任何信息的MA2格式,它在MA2中只能被近似到最接近的1/384分音上。 |
16 | | - - 此外还有一个重要的区别是,对于持续了一段时间的Hold或Slide、在其持续过程中BPM发生了变化的情况,MA2和Simai的定义也是完全不一样的。MA2在把“小节时间”计算为绝对时间时,会严格按照BPM表的声明、考虑BPM的变化;而Simai则被规定为仅按照音符开始时刻的BPM为基准,不考虑BPM的变化。详见下文(关于时间格式)[#关于时间格式]部分所述。 |
| 16 | + - 此外还有一个重要的区别是,对于持续了一段时间的Hold或Slide、在其持续过程中BPM发生了变化的情况,MA2和Simai的定义也是完全不一样的。MA2在把“小节时间”计算为绝对时间时,会严格按照BPM表的声明、考虑BPM的变化;而Simai则被规定为仅按照音符开始时刻的BPM为基准,不考虑BPM的变化。详见下文[关于时间格式](#关于时间格式)部分所述。 |
17 | 17 | - 因此,MuConvert的另一个设计目标是:在中间表示(IR)中不丢失任何信息。 |
18 | 18 | - 从源语言到IR的过程,即parser,确保是**无损**的、可以记录下来关于这个谱面的所有信息。这样可以有利于维护,也为将来的发展提供了更大的可扩展性。 |
19 | 19 | - 而在从IR到目标语言的过程,即genertaor,则会根据目标语言的表达能力,进行必要的**近似**,所有的信息丢失都发生在generator中。 |
20 | 20 |
|
| 21 | +### 编译为单文件exe模式 |
| 22 | +> 这样就不用带着一堆依赖一起发给别人了,只发一个exe就行。 |
| 23 | +```shell |
| 24 | +dotnet publish -c Release -r win-x64 -p:SelfContained=false -p UseAppHost=true -p:PublishSingleFile=true |
| 25 | +``` |
| 26 | +注意:以上命令以Release模式编译,且设置了`SelfContained=false`,即不会把.NET运行时打包进来,这样出来的exe只有几M大,但要求用户电脑上必须有.NET 10 Runtime才能运行。 |
| 27 | +如果有必要,可自行将`SelfContained`改为true,这样就会打包一个完整的.NET运行时进去(出来的exe有大几十M),但是确保用户可以运行。 |
| 28 | + |
21 | 29 | ### 关于时间格式 |
22 | 30 | - 与其他库可能有所不同的一点是,本程序的底层使用“小节时间”(`Bar`)作为核心的时间格式表示。 |
23 | 31 | - “小节时间”是一个**分数**,指从谱面开头所经过的小节数。 |
|
29 | 37 | - 举一个具体的例子:对下述的总长为一小节、但横跨120BPM和60BPM区间的星星, |
30 | 38 | - 对`(120){2}1h[1:1],(60){2},`在`simai`中这个hold的时长是120BPM下的1小节即2s; |
31 | 39 | - 然而对看似等价的表述`BPM 0 0 120; BPM 0 192 60; NMHLD 0 0 0 384`,这个hold的持续时长是它落在120BPM的那半小节(1s)+落在60BPM的那半小节(2s),总共是3s。 |
32 | | - - 因此,在`Duration`中会进一步的把底层的数据存储类型分为`Bar`和`InvarientBar`,对应于以上的两种情况。 |
| 40 | + - 因此,在`Duration`中会进一步的把底层的数据存储类型分为`Bar`和`InvarientBar`,对应于以上的两种情况。 |
| 41 | + |
| 42 | +### 关于parser的技术选型 |
| 43 | +- SimaiParser,考虑到Simai是一个相对复杂的格式化语法、本质是一种DSL,所以采用了[ANTLR](https://github.com/antlr/antlr4/blob/master/doc/index.md)进行解析。 |
| 44 | + - ANTLR的核心是`g4`语法文件,因此在我们的代码里编写了针对Simai语言的语法定义文件:`Simai.g4`。如需修改,请自行学习ANTLR的文档。 |
| 45 | + - ANTLR本身是不特定于编程语言的(它提供了各种编程语言的SDK),而语法文件的作用是,会被用于生成目标编程语言的“解析器代码”,以供调用。 |
| 46 | + - 在`MuConvert.csproj`中定义了一个`<Antlr4>`的Item,它就是用来在编译时添加一个从语法文件生成C#解析器代码的编译步骤的。生成的文件会被自动放在`obj`目录下。 |
| 47 | + - 具体的原理,请详见`parser/simai/SimaiParser.cs`中,对`MuConvert.antlr`下的各个类的引用。 |
| 48 | +- MA2的话,由于其天生就是为了机读设计的、格式相对简单,没有必要上ANTLR;而是直接逐行读取、一行内`Split('\t')`,就足以解析MA2的所有内容了。 |
0 commit comments