Skip to content

Commit 6e102ab

Browse files
committed
[+] Simai {#0.35} 这种绝对时间步长写法的支持
1 parent 813338b commit 6e102ab

6 files changed

Lines changed: 65 additions & 18 deletions

File tree

Locale.Designer.cs

Lines changed: 12 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Locale.resx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
<data name="SimaiGrammarFailed" xml:space="preserve">
101101
<value>Failed to parse simai syntax! </value>
102102
</data>
103-
<data name="AbsoluteStepNotImplemented" xml:space="preserve">
104-
<value>Absolute step tags are not supported. Use BPM + division notation such as "(120){4}".</value>
103+
<data name="AbsoluteStepUsed" xml:space="preserve">
104+
<value>The chart uses absolute time step notation like {0}. Support for this feature is experimental; if you run into issues, please report them at https://github.com/MuNet-OSS/MuConvert/issues.</value>
105105
</data>
106106
<data name="ExtraModifiersIgnored" xml:space="preserve">
107107
<value>Unexpected modifier(s): {0}. Ignored.</value>
@@ -145,4 +145,7 @@
145145
<data name="MA2CNSlideNoPrevious" xml:space="preserve">
146146
<value>Parse error: MA2 CN___ (connecting slide) has no preceding slide segment!</value>
147147
</data>
148+
<data name="StartNoBpm" xml:space="preserve">
149+
<value>No BPM was specified at the start of the chart! A `({0})` has been inserted automatically at the beginning.</value>
150+
</data>
148151
</root>

Locale.zh-hans.resx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
<data name="SimaiGrammarFailed" xml:space="preserve">
101101
<value>解析Simai语法时失败!</value>
102102
</data>
103-
<data name="AbsoluteStepNotImplemented" xml:space="preserve">
104-
<value>本程序暂不支持直接指定绝对时间步长的写法。请使用类似"(120){4}"这种BPM+几分音符的表示形式。</value>
103+
<data name="AbsoluteStepUsed" xml:space="preserve">
104+
<value>谱面中使用了类似 {0} 这种“绝对时间步长”写法。对该特性的支持是实验性的,如遇问题,请考虑通过 https://github.com/MuNet-OSS/MuConvert/issues 报告给我们。</value>
105105
</data>
106106
<data name="ExtraModifiersIgnored" xml:space="preserve">
107107
<value>不应出现的修饰符: {0}. 已忽略。</value>
@@ -145,4 +145,7 @@
145145
<data name="MA2CNSlideNoPrevious" xml:space="preserve">
146146
<value>解析错误:MA2 CN___ 连接星星,未能找到前一段的星星!</value>
147147
</data>
148+
<data name="StartNoBpm" xml:space="preserve">
149+
<value>谱面开头没有指定BPM!已自动为您添加一个`({0})`在谱面开头。</value>
150+
</data>
148151
</root>

Locale.zh-hant.resx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
<data name="SimaiGrammarFailed" xml:space="preserve">
101101
<value>解析Simai語法時失敗! </value>
102102
</data>
103-
<data name="AbsoluteStepNotImplemented" xml:space="preserve">
104-
<value>本程式暫不支援直接指定絕對時間步長的寫法。請使用類似「(120){4}」這種 BPM 加幾分音符的表示形式。</value>
103+
<data name="AbsoluteStepUsed" xml:space="preserve">
104+
<value>譜面中使用了類似 {0} 的「絕對時間步長」寫法。對此特性的支援為實驗性質;若遇到問題,請至 https://github.com/MuNet-OSS/MuConvert/issues 向我們回報。</value>
105105
</data>
106106
<data name="ExtraModifiersIgnored" xml:space="preserve">
107107
<value>不應出現的修飾符:{0}. 已忽略。</value>
@@ -145,4 +145,7 @@
145145
<data name="MA2CNSlideNoPrevious" xml:space="preserve">
146146
<value>解析錯誤:MA2 CN___ 連接星星,未能找到前一段的星星!</value>
147147
</data>
148+
<data name="StartNoBpm" xml:space="preserve">
149+
<value>譜面開頭沒有指定 BPM!已自動在譜面開頭加入 `({0})`。</value>
150+
</data>
148151
</root>

parser/simai/Simai.g4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ chart: (notations ',')* CHART_END? EOF;
4040

4141
notations // 同一时刻的所有标记,包括note标记、bpm标记等等
4242
: (bpmTag
43-
| absulouteStepTag // 暂不支持,但这毕竟是合法的语法
43+
| absulouteStepTag
4444
| metTag
4545
| noteGroup
4646
)*;

parser/simai/SimaiParser.cs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ public class SimaiParser : SimaiBaseVisitor<object>, IParser
1616

1717
private Rational now = 0;
1818
private Rational step = new(1, 4);
19+
private decimal? absoluteTimeStep = null; // 此项必须和step本体一起更改
1920

2021
private ParserRuleContext? currContext; // 供调试报错AddAlert函数使用
2122
private Note? currNote; // 用于在部分visitor之间传递额外的参数,如visitDuration、visitSlideBody等,都需要Note对象作为参数传入的情况
2223
private readonly List<string> extraModifiers = [];
24+
private bool absoluteTimeStepWarned = false; // 用于确保Warning只打印一次
2325

2426
public SimaiParser(bool bigTouch = false, bool isUtage = false, int clockCount = 4)
2527
{
@@ -108,11 +110,22 @@ public sealed override object VisitChart(P.ChartContext context)
108110
foreach (var notations in context.notations())
109111
{
110112
VisitNotations(notations);
113+
if (chart.BpmList.Count == 0) AddDefaultBpm();
111114
now = (now + step).CanonicalForm;
112115
}
113116
return true;
114117
}
115118

119+
private void AddDefaultBpm()
120+
{
121+
// 谱面开头还没看到BPM,就看到音符(或绝对时间标记)了。这在MA2中是不允许的,MA2的BPM必须是从一开头就开始指定。
122+
// 因此,我们打印一个警告,然后帮用户补一个60。
123+
const int defaultStartBpm = 60;
124+
AddAlert(Warning, string.Format(Locale.StartNoBpm, defaultStartBpm));
125+
Utils.Assert(now == 0, "现在已经不是开头了??");
126+
chart.BpmList.Add(new BPM(now, defaultStartBpm));
127+
}
128+
116129
public sealed override object VisitNotations(P.NotationsContext context)
117130
{ // 形如 (120){4}1/1 算作一组notations
118131
foreach (var child in context.children ?? [])
@@ -121,33 +134,48 @@ public sealed override object VisitNotations(P.NotationsContext context)
121134
{
122135
VisitBpmTag(bpmTag);
123136
}
124-
else if (child is P.AbsulouteStepTagContext absoluteStepTag)
125-
{
126-
VisitAbsulouteStepTag(absoluteStepTag);
127-
}
128137
else if (child is P.MetTagContext metTag)
129138
{
130139
VisitMetTag(metTag);
131140
}
132-
else if (child is P.NoteGroupContext noteGroup)
141+
else
133142
{
134-
VisitNoteGroup(noteGroup);
143+
if (chart.BpmList.Count == 0) AddDefaultBpm();
144+
if (child is P.AbsulouteStepTagContext absoluteStepTag)
145+
{
146+
VisitAbsulouteStepTag(absoluteStepTag);
147+
}
148+
else if (child is P.NoteGroupContext noteGroup)
149+
{
150+
VisitNoteGroup(noteGroup);
151+
}
135152
}
136153
}
137154
return true;
138155
}
139156

140157
public sealed override object VisitAbsulouteStepTag(P.AbsulouteStepTagContext context)
141158
{
142-
AddAlert(Error, Locale.AbsoluteStepNotImplemented, context);
143-
throw new ConversionException(alerts);
159+
if (!absoluteTimeStepWarned)
160+
{
161+
AddAlert(Warning, string.Format(Locale.AbsoluteStepUsed, context.GetText()), context);
162+
absoluteTimeStepWarned = true;
163+
}
164+
absoluteTimeStep = (decimal)VisitNumber(context.number());
165+
var currentBpm = chart.BpmList.Last().Bpm;
166+
step = (Rational)absoluteTimeStep / (240 / (Rational)currentBpm);
167+
return true;
144168
}
145169

146170
public sealed override object VisitBpmTag(P.BpmTagContext context)
147171
{
148172
currContext = context;
149173
var bpm = (decimal)VisitNumber(context.number());
150174
chart.BpmList.Add(new BPM(now, bpm));
175+
if (absoluteTimeStep != null)
176+
{ // 如果当前处于绝对时间step模式下,则bpm变化也会引起小节制step的变化,更新之。
177+
step = (Rational)absoluteTimeStep / (240 / (Rational)bpm);
178+
}
151179
return true;
152180
}
153181

@@ -156,6 +184,7 @@ public sealed override object VisitMetTag(P.MetTagContext context)
156184
currContext = context;
157185
var quaver = int.Parse(context.@int().GetText());
158186
step = new Rational(1, quaver);
187+
absoluteTimeStep = null;
159188
return true;
160189
}
161190

0 commit comments

Comments
 (0)