FAILURE MAP
← Case archive

FA-81526 / MIDI event timing / Open access

Bar, beat and tick position with meter changes: bar numbers restart after a meter change · case 01

After a change to 3/4 at bar 3, the first bar in the new meter is reported as bar 1 again.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The bar number is computed within the current signature segment without adding the segment's starting bar.

VERIFIED REPAIR

Restore the segment bar origin step so that it reads `b + offset // bar_len + 1`.

Unsuccessful approach: Adding the segment start but dropping the +1 reports zero-based bar numbers.

Case contract

Input [ppq, signatures, tick]. signatures is a list of [bar_index, numerator, denominator] sorted by bar, the first at bar 0; each takes effect at the start of its bar. A beat lasts ppq*4/denominator ticks. Return [bar (1-based), beat (1-based), tick within beat]; invalid input returns None.

Why this case matters

MIDI sequencers, file readers and synth drivers depend on exact event ordering and tick/time arithmetic.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 3:
        return None
    ppq, sigs, tick = x
    if tick < 0 or not sigs or sigs[0][0] != 0:
        return None
    start = 0
    for k, (b, num, den) in enumerate(sigs):
        beat = ppq * 4 // den
        bar_len = beat * num
        next_bar = sigs[k + 1][0] if k + 1 < len(sigs) else None
        if next_bar is not None:
            span = (next_bar - b) * bar_len
            if tick >= start + span:
                start += span
                continue
        offset = tick - start
        return [offset // bar_len + 1, offset % bar_len // beat + 1, offset % beat]
    return None
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([480, [[0, 4, 4]], 0], [1, 1, 0]), ([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[1, 4, 4]], 0], None), ([480, [[0, 4, 4]], -5], None)], [([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0])], [([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64])], [([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0])], [([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 4320], [4, 1, 0]), ([480, [[0, 3, 16]], 700], [2, 3, 100]), ([120, [[0, 4, 4], [4, 6, 8], [6, 4, 4]], 2000], [5, 2, 20])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
oracle 0[1, 1, 0][1, 1, 0]Passed
oracle 1[2, 1, 0][2, 1, 0]Passed
oracle 2[2, 2, 0][2, 2, 0]Passed
oracle 3[1, 4, 0][1, 4, 0]Passed
oracle 4[1, 1, 0][3, 1, 0]Failed
oracle 5[2, 1, 20][4, 1, 20]Failed
oracle 6NoneNonePassed
oracle 7NoneNonePassed

SHA-256 / 7338336a9beddb8170c3c526b43e29c29252997d77b6296f9b00a366e9914200

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 3:
        return None
    ppq, sigs, tick = x
    if tick < 0 or not sigs or sigs[0][0] != 0:
        return None
    start = 0
    for k, (b, num, den) in enumerate(sigs):
        beat = ppq * 4 // den
        bar_len = beat * num
        next_bar = sigs[k + 1][0] if k + 1 < len(sigs) else None
        if next_bar is not None:
            span = (next_bar - b) * bar_len
            if tick >= start + span:
                start += span
                continue
        offset = tick - start
        return [b + offset // bar_len, offset % bar_len // beat + 1, offset % beat]
    return None
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([480, [[0, 4, 4]], 0], [1, 1, 0]), ([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[1, 4, 4]], 0], None), ([480, [[0, 4, 4]], -5], None)], [([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0])], [([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64])], [([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0])], [([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 4320], [4, 1, 0]), ([480, [[0, 3, 16]], 700], [2, 3, 100]), ([120, [[0, 4, 4], [4, 6, 8], [6, 4, 4]], 2000], [5, 2, 20])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
oracle 0[0, 1, 0][1, 1, 0]Failed
oracle 1[1, 1, 0][2, 1, 0]Failed
oracle 2[1, 2, 0][2, 2, 0]Failed
oracle 3[0, 4, 0][1, 4, 0]Failed
oracle 4[2, 1, 0][3, 1, 0]Failed
oracle 5[3, 1, 20][4, 1, 20]Failed
oracle 6NoneNonePassed
oracle 7NoneNonePassed

SHA-256 / a1cbf7185c8bb53307048389d3044c3fea86db504e0a4f4568c1e6880ddd6920

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 3:
        return None
    ppq, sigs, tick = x
    if tick < 0 or not sigs or sigs[0][0] != 0:
        return None
    start = 0
    for k, (b, num, den) in enumerate(sigs):
        beat = ppq * 4 // den
        bar_len = beat * num
        next_bar = sigs[k + 1][0] if k + 1 < len(sigs) else None
        if next_bar is not None:
            span = (next_bar - b) * bar_len
            if tick >= start + span:
                start += span
                continue
        offset = tick - start
        return [b + offset // bar_len + 1, offset % bar_len // beat + 1, offset % beat]
    return None
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([480, [[0, 4, 4]], 0], [1, 1, 0]), ([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[1, 4, 4]], 0], None), ([480, [[0, 4, 4]], -5], None)], [([480, [[0, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0])], [([480, [[0, 4, 4]], 2400], [2, 2, 0]), ([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 3, 4]], 1450], [2, 1, 10]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64])], [([480, [[0, 6, 8]], 720], [1, 4, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 3840], [3, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5300], [4, 1, 20]), ([480, [[0, 2, 2]], 1000], [1, 2, 40]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0])], [([480, [[0, 6, 8]], 1440], [2, 1, 0]), ([480, [[0, 4, 4], [2, 3, 4]], 5280], [4, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 336], [2, 1, 0]), ([96, [[0, 7, 8], [1, 4, 4]], 400], [2, 1, 64]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 1920], [2, 1, 0]), ([480, [[0, 4, 4], [1, 5, 8], [3, 4, 4]], 4320], [4, 1, 0]), ([480, [[0, 3, 16]], 700], [2, 3, 100]), ([120, [[0, 4, 4], [4, 6, 8], [6, 4, 4]], 2000], [5, 2, 20])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
oracle 0[1, 1, 0][1, 1, 0]Passed
oracle 1[2, 1, 0][2, 1, 0]Passed
oracle 2[2, 2, 0][2, 2, 0]Passed
oracle 3[1, 4, 0][1, 4, 0]Passed
oracle 4[3, 1, 0][3, 1, 0]Passed
oracle 5[4, 1, 20][4, 1, 20]Passed
oracle 6NoneNonePassed
oracle 7NoneNonePassed

SHA-256 / 560b74a601005573d593a61ef187278edacaa249141a47b6c78cee730c7ce641

Verification & scope

A deterministic bounded teaching model with a stipulated toy contract; it is not a complete Standard MIDI File or MIDI 1.0/2.0 implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:50:03.795215+00:00.

Case digest / 6e9e9f8620ff30d02416fdf185d64630cc0b7fbf1aada2450e36f217ee9bc049