prompt:
Symbols like C/Ebm or C/E/G are accepted as if the bass were plain Eb or E.

Input a chord symbol: root letter with optional # or b, a quality from "", m, dim, aug, 7, maj7, m7, m7b5, dim7, sus4, mMaj7, 6, and optionally "/" plus a bass note (letter with optional # or b and nothing else). Return pitch classes root-first in template order; for a slash chord the bass moves to the front (removed from its old position if it is a chord tone, otherwise added). Unknown or malformed symbols return None.

split: open-access


meaning: Fixture-count band, not measured model difficulty

deps: stdlib

prompt:
An A major triad returns [9,13,16] instead of [9,1,4].

Input a chord symbol: root letter with optional # or b, a quality from "", m, dim, aug, 7, maj7, m7, m7b5, dim7, sus4, mMaj7, 6, and optionally "/" plus a bass note (letter with optional # or b and nothing else). Return pitch classes root-first in template order; for a slash chord the bass moves to the front (removed from its old position if it is a chord tone, otherwise added). Unknown or malformed symbols return None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality == 'maj' else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 3, 'aug'], 'III+')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'major', 0, 'aug'], 'I+')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([7, 'major', 2, 'maj'], 'V'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'lydian', 0, 'maj'], None), ([0, 'major', 0, 'sus'], None), ([5, 'minor', 4, 'dim'], 'vii°')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality != 'min' else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 3, 'aug'], 'III+')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'major', 0, 'aug'], 'I+')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([7, 'major', 2, 'maj'], 'V'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'lydian', 0, 'maj'], None), ([0, 'major', 0, 'sus'], None), ([5, 'minor', 4, 'dim'], 'vii°')]]
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)

prompt:
An augmented mediant in minor is labelled iii+ instead of III+.

Input [tonic_pc, mode, root_pc, quality] with mode major or minor (natural minor scale 0 2 3 5 7 8 10) and quality maj, min, dim or aug. Diatonic roots use their degree; in minor the leading tone (11 semitones) is degree VII with no prefix. Other roots in major are written b + the degree a semitone above; in minor # + the degree a semitone below. Numerals are uppercase for maj and aug, lowercase for min and dim, with suffix ° for dim and + for aug. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel - 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 6, 'dim'], 'bv°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([2, 'major', 1, 'dim'], 'vii°')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 6, 'dim'], 'bv°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([2, 'major', 1, 'dim'], 'vii°')]]
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)

prompt:
The borrowed flat-six chord in C major is labelled bV instead of bVI.

Input [tonic_pc, mode, root_pc, quality] with mode major or minor (natural minor scale 0 2 3 5 7 8 10) and quality maj, min, dim or aug. Diatonic roots use their degree; in minor the leading tone (11 semitones) is degree VII with no prefix. Other roots in major are written b + the degree a semitone above; in minor # + the degree a semitone below. Numerals are uppercase for maj and aug, lowercase for min and dim, with suffix ° for dim and + for aug. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi')], [([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel in (11, 9):
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi')], [([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 6, 'min'], '#vi'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([5, 'minor', 4, 'dim'], 'vii°')], [([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V')]]
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)

prompt:
In A minor the G# diminished chord is labelled #vii° instead of vii°.

Input [tonic_pc, mode, root_pc, quality] with mode major or minor (natural minor scale 0 2 3 5 7 8 10) and quality maj, min, dim or aug. Diatonic roots use their degree; in minor the leading tone (11 semitones) is degree VII with no prefix. Other roots in major are written b + the degree a semitone above; in minor # + the degree a semitone below. Numerals are uppercase for maj and aug, lowercase for min and dim, with suffix ° for dim and + for aug. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': '', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 3, 'dim'], '#iv°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°'), ([5, 'minor', 4, 'dim'], 'vii°')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list) or len(x) != 4:
        return None
    tonic, mode, root, quality = x
    scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
    if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
        return None
    if not all(isinstance(v, int) for v in (tonic, root)):
        return None
    rel = (root - tonic) % 12
    scale = scales[mode]
    names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
    prefix = ''
    if rel in scale:
        deg = scale.index(rel)
    elif mode == 'minor' and rel == 11:
        deg = 6
    elif mode == 'major':
        prefix = 'b'
        deg = scale.index((rel + 1) % 12)
    else:
        prefix = '#'
        deg = scale.index((rel - 1) % 12)
    numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
    suffix = {'maj': '', 'min': '', 'dim': 'o', 'aug': '+'}[quality]
    return prefix + numeral + suffix
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 3, 'dim'], '#iv°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°'), ([5, 'minor', 4, 'dim'], 'vii°')]]
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)

prompt:
The leading-tone chord in C major is labelled vii with no diminished marker.

Input [tonic_pc, mode, root_pc, quality] with mode major or minor (natural minor scale 0 2 3 5 7 8 10) and quality maj, min, dim or aug. Diatonic roots use their degree; in minor the leading tone (11 semitones) is degree VII with no prefix. Other roots in major are written b + the degree a semitone above; in minor # + the degree a semitone below. Numerals are uppercase for maj and aug, lowercase for min and dim, with suffix ° for dim and + for aug. Invalid input returns None.

split: open-access


prompt:
Parallel twelfths (G5 over C4 moving to A5 over D4) and parallel double octaves are not reported.

Input [upper, lower], equal-length lists of MIDI pitches. For each adjacent pair of positions i, i+1 report [i, "P5"] or [i, "P8"] when the interval (upper - lower) mod 12 is 7 or 0 at both positions (the same class), both voices move (no repeated note in either), and they move in the same direction. Return the list in order; unequal lengths return None.

split: open-access


prompt:
An octave to a compound octave by a leap in one voice while the other holds (C5/C4 to C6/C4) is flagged as parallel.

Input [upper, lower], equal-length lists of MIDI pitches. For each adjacent pair of positions i, i+1 report [i, "P5"] or [i, "P8"] when the interval (upper - lower) mod 12 is 7 or 0 at both positions (the same class), both voices move (no repeated note in either), and they move in the same direction. Return the list in order; unequal lengths return None.

split: open-access


prompt:
Contrary motion from an octave to a compound octave (C5 over C4 to G5 over G3) is reported as parallel octaves.

Input [upper, lower], equal-length lists of MIDI pitches. For each adjacent pair of positions i, i+1 report [i, "P5"] or [i, "P8"] when the interval (upper - lower) mod 12 is 7 or 0 at both positions (the same class), both voices move (no repeated note in either), and they move in the same direction. Return the list in order; unequal lengths return None.

split: open-access


prompt:
Similar motion from a fifth to an octave (G4/C4 to D5/D4) is reported as a parallel perfect interval.

Input [upper, lower], equal-length lists of MIDI pitches. For each adjacent pair of positions i, i+1 report [i, "P5"] or [i, "P8"] when the interval (upper - lower) mod 12 is 7 or 0 at both positions (the same class), both voices move (no repeated note in either), and they move in the same direction. Return the list in order; unequal lengths return None.

split: open-access


prompt:
A melody spanning exactly the instrument range (C4 to C5 into 60..72) is rejected.

Input [notes, semitones, lo, hi]. Transpose every note by the semitone amount, then shift the whole melody by the octave offset k (|k| <= 10) of smallest magnitude that places every note within [lo, hi] inclusive. Return the notes, or None if the melody is empty, lo > hi, or no octave fits.

split: open-access


prompt:
A melody that already fits a wide range is dropped several octaves to the lowest register that still fits.

Input [notes, semitones, lo, hi]. Transpose every note by the semitone amount, then shift the whole melody by the octave offset k (|k| <= 10) of smallest magnitude that places every note within [lo, hi] inclusive. Return the notes, or None if the melody is empty, lo > hi, or no octave fits.

split: open-access


prompt:
A note exactly on the lowest or highest playable pitch forces an unnecessary octave shift or rejection.

Input [notes, semitones, lo, hi]. Transpose every note by the semitone amount, then shift the whole melody by the octave offset k (|k| <= 10) of smallest magnitude that places every note within [lo, hi] inclusive. Return the notes, or None if the melody is empty, lo > hi, or no octave fits.

split: open-access


prompt:
The requested transposition is lost from the output; only the octave shift is applied.

Input [notes, semitones, lo, hi]. Transpose every note by the semitone amount, then shift the whole melody by the octave offset k (|k| <= 10) of smallest magnitude that places every note within [lo, hi] inclusive. Return the notes, or None if the melody is empty, lo > hi, or no octave fits.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n >= 8:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('d8', 'A1'), ('m9', 'M7')], [('P4', 'P5'), ('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('m9', 'M7'), ('P22', 'P1')], [('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P12', 'P4'), ('d8', 'A1'), ('m9', 'M7'), ('A8', 'd1')], [('P8', 'P1'), ('M10', 'm6'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('m9', 'M7'), ('P22', 'P1')], [('P15', 'P1'), ('dd5', 'AA4'), ('A1', 'd8'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('A8', 'd1')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 9:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('d8', 'A1'), ('m9', 'M7')], [('P4', 'P5'), ('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('m9', 'M7'), ('P22', 'P1')], [('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P12', 'P4'), ('d8', 'A1'), ('m9', 'M7'), ('A8', 'd1')], [('P8', 'P1'), ('M10', 'm6'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('m9', 'M7'), ('P22', 'P1')], [('P15', 'P1'), ('dd5', 'AA4'), ('A1', 'd8'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('A8', 'd1')]]
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)

prompt:
P8 inverts to P8 instead of P1 because the octave is first reduced to a unison.

Input an interval string: quality from P, M, m, A, d, AA, dd followed by a positive integer. Compound numbers above 8 reduce by 7 until <= 8. P is valid only for 1, 4, 5, 8; M and m only for 2, 3, 6, 7. Inversion maps M<->m, A<->d, AA<->dd, P->P and number n -> 9-n. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(8 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('P5', 'P4'), ('P1', 'P8'), ('A1', 'd8'), ('P3', None), ('M4', None), ('X3', None), ('M0', None)], [('M3', 'm6'), ('m3', 'M6'), ('P4', 'P5'), ('P1', 'P8'), ('A1', 'd8'), ('M0', None), ('M', None), ('3', None)], [('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('A1', 'd8')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('A1', 'd8')], [('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P15', 'P1'), ('A1', 'd8')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str((9 - n) % 8)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('P5', 'P4'), ('P1', 'P8'), ('A1', 'd8'), ('P3', None), ('M4', None), ('X3', None), ('M0', None)], [('M3', 'm6'), ('m3', 'M6'), ('P4', 'P5'), ('P1', 'P8'), ('A1', 'd8'), ('M0', None), ('M', None), ('3', None)], [('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('A1', 'd8')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('A1', 'd8')], [('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P15', 'P1'), ('A1', 'd8')]]
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)

prompt:
M3 inverts to m5 and P4 to P4: every inverted number is one too small.

Input an interval string: quality from P, M, m, A, d, AA, dd followed by a positive integer. Compound numbers above 8 reduce by 7 until <= 8. P is valid only for 1, 4, 5, 8; M and m only for 2, 3, 6, 7. Inversion maps M<->m, A<->d, AA<->dd, P->P and number n -> 9-n. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 4, 5)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('M4', None)], [('P4', 'P5'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P15', 'P1'), ('P12', 'P4'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P8', 'P1'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P8', 'P1'), ('P15', 'P1'), ('A1', 'd8'), ('d8', 'A1'), ('M6', 'm3'), ('m9', 'M7'), ('M4', None)]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x.rstrip('0123456789')
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('M4', None)], [('P4', 'P5'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P15', 'P1'), ('P12', 'P4'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P8', 'P1'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('M4', None), ('P22', 'P1')], [('P4', 'P5'), ('P8', 'P1'), ('P15', 'P1'), ('A1', 'd8'), ('d8', 'A1'), ('M6', 'm3'), ('m9', 'M7'), ('M4', None)]]
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)

prompt:
P8 and P15 are rejected while M8 would be accepted.

Input an interval string: quality from P, M, m, A, d, AA, dd followed by a positive integer. Compound numbers above 8 reduce by 7 until <= 8. P is valid only for 1, 4, 5, 8; M and m only for 2, 3, 6, 7. Inversion maps M<->m, A<->d, AA<->dd, P->P and number n -> 9-n. Invalid input returns None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x[0]
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('M10', 'm6'), ('AA4', 'dd5'), ('A11', 'd5'), ('dd7', 'AA2')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('P15', 'P1'), ('dd5', 'AA4'), ('AA6', 'dd3'), ('m14', 'M2')], [('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd7', 'AA2'), ('P22', 'P1')], [('m7', 'M2'), ('M10', 'm6'), ('dd5', 'AA4'), ('A1', 'd8'), ('d8', 'A1'), ('M6', 'm3'), ('A11', 'd5'), ('AA6', 'dd3')], [('P15', 'P1'), ('AA4', 'dd5'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('dd7', 'AA2'), ('m14', 'M2')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
    if not isinstance(x, str):
        return None
    q = x[:-1]
    digits = x[len(q):]
    if q not in swap or not digits.isdigit() or int(digits) < 1:
        return None
    n = int(digits)
    while n > 8:
        n -= 7
    perfect = n in (1, 4, 5, 8)
    if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
        return None
    return swap[q] + str(9 - n)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('M10', 'm6'), ('AA4', 'dd5'), ('A11', 'd5'), ('dd7', 'AA2')], [('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('A4', 'd5'), ('P15', 'P1'), ('dd5', 'AA4'), ('AA6', 'dd3'), ('m14', 'M2')], [('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd7', 'AA2'), ('P22', 'P1')], [('m7', 'M2'), ('M10', 'm6'), ('dd5', 'AA4'), ('A1', 'd8'), ('d8', 'A1'), ('M6', 'm3'), ('A11', 'd5'), ('AA6', 'dd3')], [('P15', 'P1'), ('AA4', 'dd5'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('dd7', 'AA2'), ('m14', 'M2')]]
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)

prompt:
Doubly augmented and doubly diminished intervals such as AA4 are rejected.

Input an interval string: quality from P, M, m, A, d, AA, dd followed by a positive integer. Compound numbers above 8 reduce by 7 until <= 8. P is valid only for 1, 4, 5, 8; M and m only for 2, 3, 6, 7. Inversion maps M<->m, A<->d, AA<->dd, P->P and number n -> 9-n. Invalid input returns None.

split: open-access


prompt:
Notes a few steps below the tonic jump up an octave after transposition (B3 up two steps in C gives D5).

Input [tonic, notes, steps] where tonic is a MIDI reference note. Each note must belong to the major scale on the tonic (else return None). Its scale position is its degree plus 7 per octave counted from the tonic note with floor division (notes below the tonic note are in negative octaves). Move by the signed number of steps and return the resulting MIDI notes.

split: open-access


prompt:
B4 up one step in C major gives C4 instead of C5: the result wraps within the original octave.

Input [tonic, notes, steps] where tonic is a MIDI reference note. Each note must belong to the major scale on the tonic (else return None). Its scale position is its degree plus 7 per octave counted from the tonic note with floor division (notes below the tonic note are in negative octaves). Move by the signed number of steps and return the resulting MIDI notes.

split: open-access


prompt:
A C# in C major is silently lowered to C and transposed instead of rejecting the input.

Input [tonic, notes, steps] where tonic is a MIDI reference note. Each note must belong to the major scale on the tonic (else return None). Its scale position is its degree plus 7 per octave counted from the tonic note with floor division (notes below the tonic note are in negative octaves). Move by the signed number of steps and return the resulting MIDI notes.

split: open-access


prompt:
F and every degree above E are assigned the wrong degree, so G up one step becomes G again.

Input [tonic, notes, steps] where tonic is a MIDI reference note. Each note must belong to the major scale on the tonic (else return None). Its scale position is its degree plus 7 per octave counted from the tonic note with floor division (notes below the tonic note are in negative octaves). Move by the signed number of steps and return the resulting MIDI notes.

split: open-access


prompt:
C#4 or Bb3 are rejected as malformed even though accidentals do not change staff position.

Input [note, clef] where note is a letter, accidentals (# b x, ignored for placement) and a nonnegative octave, and clef is treble (bottom line E4), bass (G2), alto (F3) or tenor (D3). Position counts diatonic steps above the bottom line (lines are even positions 0..8). Ledger lines: below the staff (-position)//2 for negative positions, above (position-8)//2 for positions over 8, else 0. Return [position, ledgers] or None when invalid.

split: open-access


prompt:
Notes outside the reference octave land dozens of positions away (C5 in treble at position 18).

Input [note, clef] where note is a letter, accidentals (# b x, ignored for placement) and a nonnegative octave, and clef is treble (bottom line E4), bass (G2), alto (F3) or tenor (D3). Position counts diatonic steps above the bottom line (lines are even positions 0..8). Ledger lines: below the staff (-position)//2 for negative positions, above (position-8)//2 for positions over 8, else 0. Return [position, ledgers] or None when invalid.

split: open-access


prompt:
B3 in treble clef (just below middle C) reports two ledger lines instead of one.

Input [note, clef] where note is a letter, accidentals (# b x, ignored for placement) and a nonnegative octave, and clef is treble (bottom line E4), bass (G2), alto (F3) or tenor (D3). Position counts diatonic steps above the bottom line (lines are even positions 0..8). Ledger lines: below the staff (-position)//2 for negative positions, above (position-8)//2 for positions over 8, else 0. Return [position, ledgers] or None when invalid.

split: open-access


prompt:
G5 above the treble staff reports a ledger line although it sits on top of the staff.

Input [note, clef] where note is a letter, accidentals (# b x, ignored for placement) and a nonnegative octave, and clef is treble (bottom line E4), bass (G2), alto (F3) or tenor (D3). Position counts diatonic steps above the bottom line (lines are even positions 0..8). Ledger lines: below the staff (-position)//2 for negative positions, above (position-8)//2 for positions over 8, else 0. Return [position, ledgers] or None when invalid.

split: open-access


prompt:
Middle C in alto clef is placed on the bottom line instead of the middle line.

Input [note, clef] where note is a letter, accidentals (# b x, ignored for placement) and a nonnegative octave, and clef is treble (bottom line E4), bass (G2), alto (F3) or tenor (D3). Position counts diatonic steps above the bottom line (lines are even positions 0..8). Ledger lines: below the staff (-position)//2 for negative positions, above (position-8)//2 for positions over 8, else 0. Return [position, ledgers] or None when invalid.

split: open-access


broken_source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
        return None
    rel = (tonic - pitch) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling == 'sharp':
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 71, 'flat'], 'ti'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'flat'], 'ra'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([3, 1, 'sharp'], 'li')]]
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)

source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
        return None
    rel = abs(pitch - tonic) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling == 'sharp':
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 71, 'flat'], 'ti'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'flat'], 'ra'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([3, 1, 'sharp'], 'li')]]
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)

prompt:
In C, the note D is sung te or li instead of re because the distance is measured from pitch to tonic.

Input [tonic_pc, pitch, spelling] with integer pitch values and spelling sharp or flat. The relative pitch class (pitch - tonic) mod 12 maps diatonic degrees to do re mi fa sol la ti; chromatic degrees use di ri fi si li for sharp spelling and ra me se le te for flat spelling. Invalid input returns None.

split: open-access


broken_source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
        return None
    rel = (pitch - tonic) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling != 'sharp':
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti')], [([0, 71, 'flat'], 'ti'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa')], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None)], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([2, 63, 'flat'], 'ra'), ([4, 69, 'sharp'], 'fa')]]
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)

source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
        return None
    rel = (pitch - tonic) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling == 'sharp' or rel == 6:
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti')], [([0, 71, 'flat'], 'ti'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa')], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None)], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([2, 63, 'flat'], 'ra'), ([4, 69, 'sharp'], 'fa')]]
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)

prompt:
Raised degrees are sung with flat syllables (ra, me) when sharp spelling is requested and vice versa.

Input [tonic_pc, pitch, spelling] with integer pitch values and spelling sharp or flat. The relative pitch class (pitch - tonic) mod 12 maps diatonic degrees to do re mi fa sol la ti; chromatic degrees use di ri fi si li for sharp spelling and ra me se le te for flat spelling. Invalid input returns None.

split: open-access


broken_source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling is None:
        return None
    rel = (pitch - tonic) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling == 'sharp':
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 65, 'weird'], None)], [([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None)], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([0, 65, 'weird'], None)], [([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None)], [([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')]]
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)

source:
"""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
    tonic, pitch, spelling = x
    if not isinstance(tonic, int) or not isinstance(pitch, int) or not isinstance(spelling, str):
        return None
    rel = (pitch - tonic) % 12
    diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
    if rel in diatonic:
        return diatonic[rel]
    if spelling == 'sharp':
        return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
    return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 65, 'weird'], None)], [([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None)], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([0, 65, 'weird'], None)], [([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None)], [([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')]]
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)

prompt:
An unknown spelling such as "weird" yields flat syllables instead of None.

Input [tonic_pc, pitch, spelling] with integer pitch values and spelling sharp or flat. The relative pitch class (pitch - tonic) mod 12 maps diatonic degrees to do re mi fa sol la ti; chromatic degrees use di ri fi si li for sharp spelling and ra me se le te for flat spelling. Invalid input returns None.

split: open-access


prompt:
An unordered voicing such as [72,64,67] is reported in root position instead of first inversion.

Input 3 or 4 MIDI integers in any order. The pitch-class set must match a template relative to some root (triads 047 037 036 048; sevenths 047t 037t 047e 036t 0369, t=10 e=11); roots are tried in ascending pitch-class order. The bass is the lowest MIDI note. Return [root_pc, figure] with figures "", "6", "64" for triads and "7", "65", "43", "42" for sevenths by the bass position in the template; otherwise None.

split: open-access


prompt:
A four-note triad with a doubled root (C E G C) is labelled with seventh figures ("7") instead of root position.

Input 3 or 4 MIDI integers in any order. The pitch-class set must match a template relative to some root (triads 047 037 036 048; sevenths 047t 037t 047e 036t 0369, t=10 e=11); roots are tried in ascending pitch-class order. The bass is the lowest MIDI note. Return [root_pc, figure] with figures "", "6", "64" for triads and "7", "65", "43", "42" for sevenths by the bass position in the template; otherwise None.

split: open-access


prompt:
First-inversion triads are labelled 64 and second-inversion triads 6.

Input 3 or 4 MIDI integers in any order. The pitch-class set must match a template relative to some root (triads 047 037 036 048; sevenths 047t 037t 047e 036t 0369, t=10 e=11); roots are tried in ascending pitch-class order. The bass is the lowest MIDI note. Return [root_pc, figure] with figures "", "6", "64" for triads and "7", "65", "43", "42" for sevenths by the bass position in the template; otherwise None.

split: open-access


prompt:
Diminished seventh chords such as B D F Ab return None instead of a root and figure.

Input 3 or 4 MIDI integers in any order. The pitch-class set must match a template relative to some root (triads 047 037 036 048; sevenths 047t 037t 047e 036t 0369, t=10 e=11); roots are tried in ascending pitch-class order. The bass is the lowest MIDI note. Return [root_pc, figure] with figures "", "6", "64" for triads and "7", "65", "43", "42" for sevenths by the bass position in the template; otherwise None.

split: open-access


prompt:
Delta 128 is written as [1, 0], which a reader decodes as two separate deltas 1 and 0.

Input a delta-time integer 0..0x0FFFFFFF (booleans rejected). Encode as 7-bit groups, most significant group first, with bit 7 set on every byte except the last. Zero encodes as [0]. Out-of-range or non-integer input returns None.

split: open-access


prompt:
Delta 128 is written as [0, 129]; the terminating byte comes first and the stream desynchronises.

Input a delta-time integer 0..0x0FFFFFFF (booleans rejected). Encode as 7-bit groups, most significant group first, with bit 7 set on every byte except the last. Zero encodes as [0]. Out-of-range or non-integer input returns None.

split: open-access


prompt:
Delta 0x10000000 is encoded as five bytes instead of being rejected.

Input a delta-time integer 0..0x0FFFFFFF (booleans rejected). Encode as 7-bit groups, most significant group first, with bit 7 set on every byte except the last. Zero encodes as [0]. Out-of-range or non-integer input returns None.

split: open-access


prompt:
A zero delta between simultaneous events produces an empty byte list, so the next event byte is read as the delta.

Input a delta-time integer 0..0x0FFFFFFF (booleans rejected). Encode as 7-bit groups, most significant group first, with bit 7 set on every byte except the last. Zero encodes as [0]. Out-of-range or non-integer input returns None.

split: open-access


prompt:
Every multi-byte delta decodes too large, e.g. [129, 0] reads as 16512 instead of 128.

Input a list of byte values. Decode consecutive variable-length quantities (7 data bits per byte, bit 7 = continuation, most significant first, at most 4 bytes each). Return the list of values; return None for a byte outside 0..255, a quantity whose fourth byte still has the continuation bit, or a truncated final quantity.

split: open-access


prompt:
A malformed five-byte quantity is decoded as a 35-bit value instead of being rejected.

Input a list of byte values. Decode consecutive variable-length quantities (7 data bits per byte, bit 7 = continuation, most significant first, at most 4 bytes each). Return the list of values; return None for a byte outside 0..255, a quantity whose fourth byte still has the continuation bit, or a truncated final quantity.

split: open-access


prompt:
In [0, 129, 0, 5] the second and third values absorb earlier bits instead of reading 128 and 5.

Input a list of byte values. Decode consecutive variable-length quantities (7 data bits per byte, bit 7 = continuation, most significant first, at most 4 bytes each). Return the list of values; return None for a byte outside 0..255, a quantity whose fourth byte still has the continuation bit, or a truncated final quantity.

split: open-access


prompt:
A stream ending in a byte with the continuation bit set, like [129], returns [] instead of None.

Input a list of byte values. Decode consecutive variable-length quantities (7 data bits per byte, bit 7 = continuation, most significant first, at most 4 bytes each). Return the list of values; return None for a byte outside 0..255, a quantity whose fourth byte still has the continuation bit, or a truncated final quantity.

split: open-access


prompt:
Every normal header (length 00 00 00 06) is rejected because the length reads as 100663296.

Input the bytes of a header chunk: "MThd", a 32-bit big-endian length (>= 6; extra bytes ignored but must be present), 16-bit format (0, 1, 2), 16-bit track count (nonzero; exactly 1 for format 0) and 16-bit division. If bit 15 of division is set, the high byte is a negative two's-complement frame rate (24, 25, 29, 30) and the low byte ticks per frame; otherwise division is ticks per quarter note (nonzero). Return a dict or None.

split: open-access


prompt:
Every SMPTE-timed file is rejected: 0xE8 (-24) is read as 104 frames per second.

Input the bytes of a header chunk: "MThd", a 32-bit big-endian length (>= 6; extra bytes ignored but must be present), 16-bit format (0, 1, 2), 16-bit track count (nonzero; exactly 1 for format 0) and 16-bit division. If bit 15 of division is set, the high byte is a negative two's-complement frame rate (24, 25, 29, 30) and the low byte ticks per frame; otherwise division is ticks per quarter note (nonzero). Return a dict or None.

split: open-access


prompt:
A format 0 header declaring two tracks is accepted instead of rejected.

Input the bytes of a header chunk: "MThd", a 32-bit big-endian length (>= 6; extra bytes ignored but must be present), 16-bit format (0, 1, 2), 16-bit track count (nonzero; exactly 1 for format 0) and 16-bit division. If bit 15 of division is set, the high byte is a negative two's-complement frame rate (24, 25, 29, 30) and the low byte ticks per frame; otherwise division is ticks per quarter note (nonzero). Return a dict or None.

split: open-access


prompt:
A header chunk declaring length 8 (with two extra bytes present) is rejected although extra bytes must be ignored.

Input the bytes of a header chunk: "MThd", a 32-bit big-endian length (>= 6; extra bytes ignored but must be present), 16-bit format (0, 1, 2), 16-bit track count (nonzero; exactly 1 for format 0) and 16-bit division. If bit 15 of division is set, the high byte is a negative two's-complement frame rate (24, 25, 29, 30) and the low byte ticks per frame; otherwise division is ticks per quarter note (nonzero). Return a dict or None.

split: open-access


prompt:
A header with division 0 is returned as ppq 0, which later divides by zero in timing code.

Input the bytes of a header chunk: "MThd", a 32-bit big-endian length (>= 6; extra bytes ignored but must be present), 16-bit format (0, 1, 2), 16-bit track count (nonzero; exactly 1 for format 0) and 16-bit division. If bit 15 of division is set, the high byte is a negative two's-complement frame rate (24, 25, 29, 30) and the low byte ticks per frame; otherwise division is ticks per quarter note (nonzero). Return a dict or None.

split: open-access


prompt:
A program change on channel 2 (C1) swallows the next delta byte as a second data byte and desynchronises the track.

Input the bytes of a track body: each event is a variable-length delta then either a meta event (FF type len data...), a status byte (bit 7 set) with its data bytes, or data bytes reusing the previous channel status (running status). Program change (Cx) and channel pressure (Dx) take one data byte, other channel messages two. Meta events cancel running status. Return [absolute tick, status, data...] for channel events and [tick, "meta", type] for meta events, or None on truncation or data without a running status.

split: open-access


prompt:
Data bytes after a meta event are decoded with the pre-meta status instead of being rejected.

Input the bytes of a track body: each event is a variable-length delta then either a meta event (FF type len data...), a status byte (bit 7 set) with its data bytes, or data bytes reusing the previous channel status (running status). Program change (Cx) and channel pressure (Dx) take one data byte, other channel messages two. Meta events cancel running status. Return [absolute tick, status, data...] for channel events and [tick, "meta", type] for meta events, or None on truncation or data without a running status.

split: open-access


prompt:
A delta of exactly 127 swallows the following status byte into the delta.

Input the bytes of a track body: each event is a variable-length delta then either a meta event (FF type len data...), a status byte (bit 7 set) with its data bytes, or data bytes reusing the previous channel status (running status). Program change (Cx) and channel pressure (Dx) take one data byte, other channel messages two. Meta events cancel running status. Return [absolute tick, status, data...] for channel events and [tick, "meta", type] for meta events, or None on truncation or data without a running status.

split: open-access


prompt:
After a meta event the parser lands on the last payload byte and reads it as the next delta.

Input the bytes of a track body: each event is a variable-length delta then either a meta event (FF type len data...), a status byte (bit 7 set) with its data bytes, or data bytes reusing the previous channel status (running status). Program change (Cx) and channel pressure (Dx) take one data byte, other channel messages two. Meta events cancel running status. Return [absolute tick, status, data...] for channel events and [tick, "meta", type] for meta events, or None on truncation or data without a running status.

split: open-access


prompt:
Event times reset after each event: the second of two events 10 ticks apart reports tick 10 regardless of history.

Input the bytes of a track body: each event is a variable-length delta then either a meta event (FF type len data...), a status byte (bit 7 set) with its data bytes, or data bytes reusing the previous channel status (running status). Program change (Cx) and channel pressure (Dx) take one data byte, other channel messages two. Meta events cancel running status. Return [absolute tick, status, data...] for channel events and [tick, "meta", type] for meta events, or None on truncation or data without a running status.

split: open-access


prompt:
Running-status style note-offs (note-on with velocity 0) never end notes; every note lasts to the end of the track.

Input time-ordered events [tick, kind, channel, note, velocity] with kind on or off. A note-on with velocity 0 acts as a note-off. Each off ends the earliest still-open note with the same channel and note (FIFO); unmatched offs are ignored. Notes still open at the end end at the last event tick. Return [start, end, channel, note, on-velocity] sorted by start, note, channel, end.

split: open-access


prompt:
With two overlapping C4 notes, the first note-off ends the later note, swapping the two durations.

Input time-ordered events [tick, kind, channel, note, velocity] with kind on or off. A note-on with velocity 0 acts as a note-off. Each off ends the earliest still-open note with the same channel and note (FIFO); unmatched offs are ignored. Notes still open at the end end at the last event tick. Return [start, end, channel, note, on-velocity] sorted by start, note, channel, end.

split: open-access


prompt:
A note-off on channel 1 ends a still-sounding note of the same pitch on channel 0.

Input time-ordered events [tick, kind, channel, note, velocity] with kind on or off. A note-on with velocity 0 acts as a note-off. Each off ends the earliest still-open note with the same channel and note (FIFO); unmatched offs are ignored. Notes still open at the end end at the last event tick. Return [start, end, channel, note, on-velocity] sorted by start, note, channel, end.

split: open-access


prompt:
A note never switched off is reported with end equal to its start instead of the final tick.

Input time-ordered events [tick, kind, channel, note, velocity] with kind on or off. A note-on with velocity 0 acts as a note-off. Each off ends the earliest still-open note with the same channel and note (FIFO); unmatched offs are ignored. Notes still open at the end end at the last event tick. Return [start, end, channel, note, on-velocity] sorted by start, note, channel, end.

split: open-access


prompt:
A long note that starts first is listed after shorter notes that start later.

Input time-ordered events [tick, kind, channel, note, velocity] with kind on or off. A note-on with velocity 0 acts as a note-off. Each off ends the earliest still-open note with the same channel and note (FIFO); unmatched offs are ignored. Notes still open at the end end at the last event tick. Return [start, end, channel, note, on-velocity] sorted by start, note, channel, end.

split: open-access


prompt:
Every event after the first carries its absolute tick as a delta, so playback drifts later and later.

Input a list of [tick, kind, note] with kind on or off in any order. Emit events sorted by tick; at equal ticks note-offs precede note-ons, and otherwise input order is kept. Each output is [delta from the previous emitted event (the first from tick 0), kind, note]. A negative tick returns None.

split: open-access


prompt:
A repeated note whose off and next on share a tick is emitted on-then-off, so a receiver cuts the new note immediately.

Input a list of [tick, kind, note] with kind on or off in any order. Emit events sorted by tick; at equal ticks note-offs precede note-ons, and otherwise input order is kept. Each output is [delta from the previous emitted event (the first from tick 0), kind, note]. A negative tick returns None.

split: open-access


prompt:
A track whose first event is at tick 5 is serialised with a first delta of 0, removing the opening rest.

Input a list of [tick, kind, note] with kind on or off in any order. Emit events sorted by tick; at equal ticks note-offs precede note-ons, and otherwise input order is kept. Each output is [delta from the previous emitted event (the first from tick 0), kind, note]. A negative tick returns None.

split: open-access


prompt:
Long files with many tempo changes drift early: fractional microseconds are discarded at every segment boundary.

Input [ppq, changes, tick] where changes are [tick, microseconds_per_quarter] in any order (a later entry at the same tick overrides an earlier one). Before the first change the tempo is 500000. Each tempo applies from its tick onward. Sum the exact time of each segment and floor once at the end. Invalid ppq or negative tick returns None.

split: open-access


prompt:
Material before the first tempo event is timed at that later tempo instead of the default 120 BPM.

Input [ppq, changes, tick] where changes are [tick, microseconds_per_quarter] in any order (a later entry at the same tick overrides an earlier one). Before the first change the tempo is 500000. Each tempo applies from its tick onward. Sum the exact time of each segment and floor once at the end. Invalid ppq or negative tick returns None.

split: open-access


prompt:
When two tempo events share a tick, the earlier-listed one is kept instead of the later override.

Input [ppq, changes, tick] where changes are [tick, microseconds_per_quarter] in any order (a later entry at the same tick overrides an earlier one). Before the first change the tempo is 500000. Each tempo applies from its tick onward. Sum the exact time of each segment and floor once at the end. Invalid ppq or negative tick returns None.

split: open-access


prompt:
After a tempo change the time before the change is counted again at the new tempo.

Input [ppq, changes, tick] where changes are [tick, microseconds_per_quarter] in any order (a later entry at the same tick overrides an earlier one). Before the first change the tempo is 500000. Each tempo applies from its tick onward. Sum the exact time of each segment and floor once at the end. Invalid ppq or negative tick returns None.

split: open-access


prompt:
120 BPM (07 A1 20) is read as 2138375 microseconds, about 28 BPM.

Input the bytes of a Set Tempo meta event: FF 51 03 followed by a 24-bit big-endian microseconds-per-quarter value (nonzero). Return [microseconds, bpm_x100] where bpm_x100 = 6000000000 / microseconds rounded half up. Anything else returns None.

split: open-access


prompt:
A malformed Set Tempo event declaring length 4 or 2 is accepted as if it were valid.

Input the bytes of a Set Tempo meta event: FF 51 03 followed by a 24-bit big-endian microseconds-per-quarter value (nonzero). Return [microseconds, bpm_x100] where bpm_x100 = 6000000000 / microseconds rounded half up. Anything else returns None.

split: open-access


prompt:
A tempo of 3840000 microseconds reports 15.62 BPM instead of 15.63.

Input the bytes of a Set Tempo meta event: FF 51 03 followed by a 24-bit big-endian microseconds-per-quarter value (nonzero). Return [microseconds, bpm_x100] where bpm_x100 = 6000000000 / microseconds rounded half up. Anything else returns None.

split: open-access


prompt:
Files using 29.97 fps timing run about 3.4% slow because each frame is taken as 1/29 second.

Input [division_high_byte, ticks_per_frame, ticks]. The high byte is a negative frame-rate code in two's complement: 24, 25, 29 (meaning 30000/1001 frames per second) or 30. Microseconds = ticks * 1000000 / (rate * ticks_per_frame), floored once. Invalid codes, non-positive ticks per frame or negative ticks return None.

split: open-access


prompt:
Every SMPTE-timed file is rejected because the rate code decodes to a negative number.

Input [division_high_byte, ticks_per_frame, ticks]. The high byte is a negative frame-rate code in two's complement: 24, 25, 29 (meaning 30000/1001 frames per second) or 30. Microseconds = ticks * 1000000 / (rate * ticks_per_frame), floored once. Invalid codes, non-positive ticks per frame or negative ticks return None.

split: open-access


prompt:
About half of all sub-frame tick positions are reported one microsecond later than the stipulated floored time.

Input [division_high_byte, ticks_per_frame, ticks]. The high byte is a negative frame-rate code in two's complement: 24, 25, 29 (meaning 30000/1001 frames per second) or 30. Microseconds = ticks * 1000000 / (rate * ticks_per_frame), floored once. Invalid codes, non-positive ticks per frame or negative ticks return None.

split: open-access


prompt:
In 6/8 the fourth eighth-note beat is reported as beat 2 because beats are measured in quarters.

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.

split: open-access


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

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.

split: open-access


prompt:
The first beat of bar 2 in 4/4 is reported as beat 5.

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.

split: open-access


prompt:
With three meters, the middle segment is treated as starting from bar 0, so positions after the last change land in the wrong bar.

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.

split: open-access


prompt:
A note just before the beat is dragged back almost a full grid step instead of forward to the beat.

Input [ticks, grid, strength] with grid > 0 and strength 0..100 percent. Each tick moves toward its nearest grid line (exact halves go to the later line) by strength percent of the distance, with the displacement truncated toward zero. Invalid parameters return None.

split: open-access


prompt:
Partial quantisation of late notes moves them one tick further than the requested strength.

Input [ticks, grid, strength] with grid > 0 and strength 0..100 percent. Each tick moves toward its nearest grid line (exact halves go to the later line) by strength percent of the distance, with the displacement truncated toward zero. Invalid parameters return None.

split: open-access


prompt:
A strength of 0 (no-op quantise) is rejected instead of returning the input unchanged.

Input [ticks, grid, strength] with grid > 0 and strength 0..100 percent. Each tick moves toward its nearest grid line (exact halves go to the later line) by strength percent of the distance, with the displacement truncated toward zero. Invalid parameters return None.

split: open-access


prompt:
With 66% swing a note late in the beat (tick 479 of a 480-tick beat) lands after the next downbeat.

Input [ticks, ppq, swing] with even ppq > 0 and swing 50..75 percent. Within each beat, positions in the first half [0, ppq/2) scale linearly onto [0, split) and positions in the second half onto [split, ppq), where split = ppq*swing/100. The remapped position is floored. Invalid parameters return None.

split: open-access


prompt:
Every offbeat is treated as a downbeat of its own, so swing never delays anything and positions double.

Input [ticks, ppq, swing] with even ppq > 0 and swing 50..75 percent. Within each beat, positions in the first half [0, ppq/2) scale linearly onto [0, split) and positions in the second half onto [split, ppq), where split = ppq*swing/100. The remapped position is floored. Invalid parameters return None.

split: open-access


prompt:
A swing of exactly 50% (straight eighths) is rejected instead of returning the input unchanged.

Input [ticks, ppq, swing] with even ppq > 0 and swing 50..75 percent. Within each beat, positions in the first half [0, ppq/2) scale linearly onto [0, split) and positions in the second half onto [split, ppq), where split = ppq*swing/100. The remapped position is floored. Invalid parameters return None.

split: open-access


prompt:
Some swung notes land one tick later than the stipulated floored position.

Input [ticks, ppq, swing] with even ppq > 0 and swing 50..75 percent. Within each beat, positions in the first half [0, ppq/2) scale linearly onto [0, split) and positions in the second half onto [split, ppq), where split = ppq*swing/100. The remapped position is floored. Invalid parameters return None.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list):
        return None
    pos = 0
    running = False
    for msg in x:
        kind = msg[0]
        if kind == 'start':
            pos = 0
            running = True
        elif kind == 'continue':
            running = True
        elif kind == 'stop':
            running = False
        elif kind == 'clock':
            if running:
                pos += 1
        elif kind == 'spp':
            if not running:
                pos = 6 * ((msg[1] << 7) | msg[2])
        else:
            return None
    return [pos, running, pos // 24]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([['start'], ['clock'], ['clock']], [2, True, 0]), ([['clock'], ['clock']], [0, False, 0]), ([['start'], ['clock'], ['stop'], ['clock'], ['continue'], ['clock']], [2, True, 0]), ([['spp', 4, 0], ['continue'], ['clock']], [25, True, 1]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['start'], ['spp', 8, 0], ['clock']], [1, True, 0]), ([['start'], ['clock'], ['stop'], ['start'], ['clock']], [1, True, 0]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0])], [([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['start'], ['spp', 8, 0], ['clock']], [1, True, 0]), ([['start'], ['clock'], ['stop'], ['start'], ['clock']], [1, True, 0]), ([['spp', 16, 0], ['start']], [0, True, 0]), ([['reset']], None), ([], [0, False, 0]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1])], [([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['reset']], None), ([], [0, False, 0]), ([['start'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock']], [25, True, 1]), ([['spp', 127, 127]], [98298, False, 4095]), ([['start'], ['clock'], ['clock'], ['stop'], ['spp', 2, 0], ['continue'], ['clock']], [13, True, 0]), ([['continue'], ['clock']], [1, True, 0]), ([['start'], ['stop'], ['continue'], ['clock']], [1, True, 0])], [([['spp', 4, 0], ['continue'], ['clock']], [25, True, 1]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['spp', 127, 127]], [98298, False, 4095]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1]), ([['continue'], ['clock']], [1, True, 0]), ([['start'], ['stop'], ['continue'], ['clock']], [1, True, 0])], [([['start'], ['clock'], ['clock']], [2, True, 0]), ([['clock'], ['clock']], [0, False, 0]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['spp', 127, 127]], [98298, False, 4095]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1]), ([['start'], ['clock'], ['clock'], ['stop'], ['spp', 2, 0], ['continue'], ['clock']], [13, True, 0])]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    if not isinstance(x, list):
        return None
    pos = 0
    running = False
    for msg in x:
        kind = msg[0]
        if kind == 'start':
            pos = 0
            running = True
        elif kind == 'continue':
            running = True
        elif kind == 'stop':
            running = False
        elif kind == 'clock':
            if running:
                pos += 1
        elif kind == 'spp':
            if not running:
                pos = 6 * ((msg[2] << 8) | msg[1])
        else:
            return None
    return [pos, running, pos // 24]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([['start'], ['clock'], ['clock']], [2, True, 0]), ([['clock'], ['clock']], [0, False, 0]), ([['start'], ['clock'], ['stop'], ['clock'], ['continue'], ['clock']], [2, True, 0]), ([['spp', 4, 0], ['continue'], ['clock']], [25, True, 1]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['start'], ['spp', 8, 0], ['clock']], [1, True, 0]), ([['start'], ['clock'], ['stop'], ['start'], ['clock']], [1, True, 0]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0])], [([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['start'], ['spp', 8, 0], ['clock']], [1, True, 0]), ([['start'], ['clock'], ['stop'], ['start'], ['clock']], [1, True, 0]), ([['spp', 16, 0], ['start']], [0, True, 0]), ([['reset']], None), ([], [0, False, 0]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1])], [([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['reset']], None), ([], [0, False, 0]), ([['start'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock'], ['clock']], [25, True, 1]), ([['spp', 127, 127]], [98298, False, 4095]), ([['start'], ['clock'], ['clock'], ['stop'], ['spp', 2, 0], ['continue'], ['clock']], [13, True, 0]), ([['continue'], ['clock']], [1, True, 0]), ([['start'], ['stop'], ['continue'], ['clock']], [1, True, 0])], [([['spp', 4, 0], ['continue'], ['clock']], [25, True, 1]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['spp', 127, 127]], [98298, False, 4095]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1]), ([['continue'], ['clock']], [1, True, 0]), ([['start'], ['stop'], ['continue'], ['clock']], [1, True, 0])], [([['start'], ['clock'], ['clock']], [2, True, 0]), ([['clock'], ['clock']], [0, False, 0]), ([['spp', 0, 1], ['continue']], [768, True, 32]), ([['spp', 1, 1]], [774, False, 32]), ([['stop'], ['spp', 3, 0], ['continue'], ['clock'], ['clock']], [20, True, 0]), ([['spp', 127, 127]], [98298, False, 4095]), ([['spp', 4, 0], ['continue'], ['stop'], ['continue'], ['clock']], [25, True, 1]), ([['start'], ['clock'], ['clock'], ['stop'], ['spp', 2, 0], ['continue'], ['clock']], [13, True, 0])]]
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)

prompt:
A pointer of 4 sixteenths (lsb 4, msb 0) locates to sixteenth 512 instead of 4.

Input a list of messages: ["start"], ["continue"], ["stop"], ["clock"] or ["spp", lsb, msb]. start resets the position to 0 and runs; continue runs from the current position; stop halts; clock advances the position by one clock only while running; a song position pointer (in sixteenth notes, 6 clocks each, 14-bit lsb/msb) is honoured only while stopped. Return [position in clocks, running, quarter notes = position // 24]; unknown messages return None.

split: open-access