babalae/better-genshin-impact · error · FormatException
无法解析 MIDI JSON 变速标记:{rawPart}
Error message
无法解析 MIDI JSON 变速标记:{rawPart} What it means
A FormatException from ParseMidiJsonTimeline raised when a pipe-delimited segment of a MIDI-JSON "notes" string starts with '*' (a tempo-change marker) but the remainder is not a strictly positive floating-point number. The '*' prefix denotes a BPM change applied from that point; an unparseable or non-positive value aborts the whole timeline build. Parse uses NumberStyles.Float with the invariant culture.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:396
var events = new List<PerformanceEvent>();
var cursor = TimeSpan.Zero;
var bpm = initialBpm;
string previousStatus = string.Empty;
string previousKeys = string.Empty;
var previousWasEvent = false;
var rawParts = sheet.Split(
'|',
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
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;
View on GitHub (pinned to a7cb36712d)
Solutions
- Inspect the notes string and fix every '*...' segment to be a positive number with a dot decimal (e.g. '*120').
- Regenerate the MIDI-JSON file from the original MIDI with the exporter.
- Strip or correct any stray '*' that is not a real tempo change.
- Wrap file loading through ParseAsync so a bad tempo yields an InvalidScore with a readable Error instead of crashing the UI.
Example fix
// before "notes":"*X|DQ:0|UQ:480" // after "notes":"*120|DQ:0|UQ:480"
Defensive patterns
Strategy: try-catch
Validate before calling
static bool MidiJsonTemposValid(string notes)
{
foreach (var part in notes.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (!part.StartsWith('*')) continue;
if (!double.TryParse(part[1..], NumberStyles.Float, CultureInfo.InvariantCulture, out var bpm) || bpm <= 0)
return false;
}
return true;
} Type guard
static bool IsValidTempoSegment(string s) => s.StartsWith('*') && double.TryParse(s[1..], NumberStyles.Float, CultureInfo.InvariantCulture, out var b) && b > 0; Try / catch
var score = await parser.ParseAsync(path, root, ct);
if (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; } Prevention
- Validate tempo segments before parsing.
- Re-export MIDI-JSON rather than hand-editing tempo tokens.
- Use ParseAsync to get InvalidScore reporting.
When it happens
Trigger: The MIDI-JSON notes string contains a segment like '*X', '**120', '*0', '*-5', or '*120,5' (comma decimal) after splitting on '|'.
Common situations: A MIDI-to-JSON exporter emitted a malformed tempo token; manual editing inserted a stray '*'; a locale conversion turned '*120.0' into '*120,0'; a 'multiply' or comment character was mistaken for a tempo marker.
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/26f48d3efb386455.
Report an issue: GitHub.