{"record":{"id":"dcc0a59d7726fc40","repo":"babalae/better-genshin-impact","slug":"midi-json-rawpart-dcc0a5","errorCode":null,"errorMessage":"无法解析 MIDI JSON 事件：{rawPart}","messagePattern":"无法解析 MIDI JSON 事件：(.+?)","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs","lineNumber":406,"sourceCode":"        for (var index = 0; index < rawParts.Length; index++)\n        {\n            var rawPart = rawParts[index];\n            if (rawPart.StartsWith('*'))\n            {\n                if (!double.TryParse(rawPart[1..], NumberStyles.Float, CultureInfo.InvariantCulture, out bpm)\n                    || bpm <= 0)\n                {\n                    throw new FormatException($\"无法解析 MIDI JSON 变速标记：{rawPart}\");\n                }\n\n                previousWasEvent = false;\n                continue;\n            }\n\n            var match = MidiJsonEventRegex().Match(rawPart);\n            if (!match.Success)\n            {\n                throw new FormatException($\"无法解析 MIDI JSON 事件：{rawPart}\");\n            }\n\n            var status = match.Groups[\"status\"].Value;\n            var keys = match.Groups[\"keys\"].Value;\n            var deltaTicks = long.Parse(match.Groups[\"ticks\"].Value, CultureInfo.InvariantCulture);\n            var delay = TimeSpan.FromMilliseconds(deltaTicks * 60000d / (bpm * ticks));\n            cursor += delay;\n\n            if (status == \"D\"\n                && previousWasEvent\n                && previousStatus == \"U\"\n                && previousKeys.Any(keys.Contains)\n                && delay.TotalMilliseconds < LowestLatencyMilliseconds)\n            {\n                cursor += TimeSpan.FromMilliseconds(LowestLatencyMilliseconds);\n            }\n            else if (status == \"U\"\n                     && keys != \"@\"","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs#L388-L424","documentation":"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.","triggerScenarios":"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 '|'.","commonSituations":"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').","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."],"exampleFix":"// before (missing colon / unknown status)\n\"notes\":\"DQ0|XQ:480\"\n// after\n\"notes\":\"DQ:0|UQ:480\"","handlingStrategy":"try-catch","validationCode":"static bool MidiJsonEventsValid(string notes, Regex r)\n{\n    foreach (var part in notes.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))\n    {\n        if (part.StartsWith('*')) continue;\n        if (!r.Match(part).Success) return false;\n    }\n    return true;\n}","typeGuard":"static bool IsValidEventSegment(string s, Regex r) => !s.StartsWith('*') && r.Match(s).Success;","tryCatchPattern":"var score = await parser.ParseAsync(path, root, ct);\nif (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; }","preventionTips":["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."],"tags":["music-score","json-parsing","input-validation","midi-json","regex"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}