babalae/better-genshin-impact · error · FormatException
无法解析 MIDI JSON 事件:{rawPart}
Error message
无法解析 MIDI JSON 事件:{rawPart} What it means
A FormatException from ParseMidiJsonTimeline thrown when a pipe-delimited segment does not start with '*' and does not match MidiJsonEventRegex (the generated source regex that recognizes an event like 'D<keys>:<ticks>' or 'U<keys>:<ticks>'). Every non-tempo segment must be a well-formed event token; anything else aborts parsing.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:406
for (var index = 0; index < rawParts.Length; index++)
{
var rawPart = rawParts[index];
if (rawPart.StartsWith('*'))
{
if (!double.TryParse(rawPart[1..], NumberStyles.Float, CultureInfo.InvariantCulture, out bpm)
|| bpm <= 0)
{
throw new FormatException($"无法解析 MIDI JSON 变速标记:{rawPart}");
}
previousWasEvent = false;
continue;
}
var match = MidiJsonEventRegex().Match(rawPart);
if (!match.Success)
{
throw new FormatException($"无法解析 MIDI JSON 事件:{rawPart}");
}
var status = match.Groups["status"].Value;
var keys = match.Groups["keys"].Value;
var deltaTicks = long.Parse(match.Groups["ticks"].Value, CultureInfo.InvariantCulture);
var delay = TimeSpan.FromMilliseconds(deltaTicks * 60000d / (bpm * ticks));
cursor += delay;
if (status == "D"
&& previousWasEvent
&& previousStatus == "U"
&& previousKeys.Any(keys.Contains)
&& delay.TotalMilliseconds < LowestLatencyMilliseconds)
{
cursor += TimeSpan.FromMilliseconds(LowestLatencyMilliseconds);
}
else if (status == "U"
&& keys != "@"View on GitHub (pinned to a7cb36712d)
Solutions
- Check the MidiJsonEventRegex definition (MusicScoreParser.cs:713, partial generated regex) and conform each segment to its 'status + keys + ":" + ticks' shape.
- Re-export the MIDI-JSON from the original MIDI file.
- Locate the offending segment via the {rawPart} value in the message and fix or remove it.
- Route the file through ParseAsync so the failure is reported as an InvalidScore.Error.
Example fix
// before (missing colon / unknown status) "notes":"DQ0|XQ:480" // after "notes":"DQ:0|UQ:480"
Defensive patterns
Strategy: try-catch
Validate before calling
static bool MidiJsonEventsValid(string notes, Regex r)
{
foreach (var part in notes.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (part.StartsWith('*')) continue;
if (!r.Match(part).Success) return false;
}
return true;
} Type guard
static bool IsValidEventSegment(string s, Regex r) => !s.StartsWith('*') && r.Match(s).Success; Try / catch
var score = await parser.ParseAsync(path, root, ct);
if (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; } Prevention
- Conform event segments to the MidiJsonEventRegex shape (status+keys+":"+ticks).
- Re-export from the source MIDI instead of editing.
- Use ParseAsync for graceful InvalidScore handling.
When it happens
Trigger: A segment such as 'DQ0' (missing the ticks delimiter), 'XQ:0' (unknown status letter), 'DQ:' (empty ticks), or stray text/punctuation after splitting the notes string on '|'.
Common situations: Hand-edited MIDI-JSON notes string with a typo in an event; exporter version change that altered the event format; copy-paste truncation; an event written with a wrong separator (e.g. 'DQ-0' instead of 'DQ:0').
Related errors
- 无法解析 MIDI JSON 变速标记:{rawPart}
- yuanqin 音符对象缺少 note 字段
- 无法解析音符 {keys} 的时值
- {format} 曲谱的 notes 必须是字符串
- 键谱出现不匹配的括号:{current}
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/dcc0a59d7726fc40.
Report an issue: GitHub.