babalae/better-genshin-impact · warning · FormatException

连音缺少 .$ 结束标记

Error message

连音缺少 .$ 结束标记

What it means

Thrown by MusicScoreParser.ParseYuanQinTimeline when a tuplet (连音) group is started but never terminated with a special token ending in '$'. The parser collects consecutive tokens matching the TupletSpecialRegex pattern; if the last collected token does not end with '$', the group is incomplete.

Source

Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:222

            }

            if (TupletSpecialRegex().IsMatch(token.Special))
            {
                var group = new List<YuanQinToken>();
                while (i < tokens.Count)
                {
                    group.Add(tokens[i]);
                    if (tokens[i].Special.EndsWith('$'))
                    {
                        break;
                    }

                    i++;
                }

                if (!group[^1].Special.EndsWith('$'))
                {
                    throw new FormatException("连音缺少 .$ 结束标记");
                }

                var totalDuration = GetNoteDuration(bpm, beatDenominator, token.Denominator);
                var weights = group.Select(x =>
                {
                    var match = TupletSpecialRegex().Match(x.Special);
                    return 1d / double.Parse(match.Groups["display"].Value, CultureInfo.InvariantCulture);
                }).ToList();
                var weightSum = weights.Sum();

                for (var groupIndex = 0; groupIndex < group.Count; groupIndex++)
                {
                    var duration = TimeSpan.FromTicks(
                        (long)Math.Round(totalDuration.Ticks * weights[groupIndex] / weightSum));
                    AddNote(events, cursor, duration, group[groupIndex].Keys);
                    cursor += duration;
                }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Inspect the yuanqin sheet for tuplet markers and ensure each group has a matching end token ending in '$' (e.g. '3.6 ... 3.$').
  2. Validate the sheet syntax before playback — pair-check tuplet start/end markers.
  3. Manually edit the score file to add the missing closing token.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate tuplet balance before parsing
var tupletStarts = Regex.Matches(sheet, @"^\d+\.[36]");
var tupletEnds = Regex.Matches(sheet, @"\.");
// Ensure each tuplet group has an end marker ending with '$'

Try / catch

var score = await parser.ParseAsync(path, rootFolder, ct);
if (!string.IsNullOrEmpty(score.Error)) { logger.LogWarning(score.Error); }

Prevention

When it happens

Trigger: A yuanqin sheet string or note array containing a tuplet start marker (e.g. '3.6') without a matching end marker (e.g. '3.$'). The while-loop exhausts available tokens or the group ends without a '$'-suffixed special.

Common situations: A score author forgot to close a tuplet group; the sheet was truncated or copy-pasted incorrectly; an OCR or conversion tool dropped the end marker.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/39d6959e6bad9b26. Report an issue: GitHub.