Skip to content

MusicXML: <fingering> on a fretted instrument imports one finger too low (written 1 becomes thumb) #2826

Description

@magmasystems

Is there an existing issue for this?

  • I have searched the existing issues

I have read the contribution rules

AI authorship

AI-assisted (disclosure block included as described in AGENTS.md)

Current Behavior

Note

AI-authored disclosure (alphatab-ai-authored-v1)

Portions of this content were authored by an AI agent. The agent has read
AGENTS.md and the human submitter accepts responsibility for
compliance with the rules in that document.

When a MusicXML score for a fretted instrument carries left-hand fingering in <notations><technical><fingering>, every value is imported one finger lower than written.

Loading the attached four-note file (MIDI program 24, acoustic nylon guitar) and reading Note.leftHandFinger:

written <fingering> imported as
1 Fingers.Thumb
2 Fingers.IndexFinger
3 Fingers.MiddleFinger
4 Fingers.AnnularFinger

Right-hand <pluck> values in the same file import correctly — p/i/m/a become Thumb/IndexFinger/MiddleFinger/AnnularFinger as expected. Only the numeric <fingering> values are shifted.

The shift is visible in rendered output. In a browser, a guitar score whose MusicXML holds the fingering sequence 4 3 4 1 3 1 displays as 3 2 3 t 2 t — so every printed fingering is wrong, and a written 1 appears as a thumb.

Expected Behavior

In MusicXML, <fingering> inside <technical> denotes the fretting-hand finger. For guitar and other fretted instruments the conventional numbering is 1 = index, 2 = middle, 3 = ring, 4 = little, with 0 for an open string — the numbering MuseScore writes and displays. <pluck> is the element that carries the plucking hand (p/i/m/a).

So <fingering>1</fingering> on a guitar part should import as the index finger and print as 1, and the sequence above should display as written: 4 3 4 1 3 1.

Steps To Reproduce

  1. Save the file in "Anything else?" below as fingering-offset.musicxml.
  2. Run:
import { readFileSync } from 'fs';
import * as alphaTab from '@coderline/alphatab';

const F = alphaTab.model.Fingers;
const score = alphaTab.importer.ScoreLoader.loadScoreFromBytes(
  new Uint8Array(readFileSync('fingering-offset.musicxml')),
  new alphaTab.Settings());

const notes = score.tracks[0].staves.flatMap(s => s.bars)
  .flatMap(b => b.voices).flatMap(v => v.beats).flatMap(b => b.notes);

console.log('program:', score.tracks[0].playbackInfo.program);
['1','2','3','4'].forEach((written, i) =>
  console.log(`<fingering>${written}</fingering> -> Fingers.${F[notes[i].leftHandFinger]}`));
  1. Observed output:
program: 24
<fingering>1</fingering> -> Fingers.Thumb
<fingering>2</fingering> -> Fingers.IndexFinger
<fingering>3</fingering> -> Fingers.MiddleFinger
<fingering>4</fingering> -> Fingers.AnnularFinger

The rendered symptom described above was observed separately, on a full guitar score displayed in a browser — not on this reduced file, which I only loaded and inspected via the API as shown.

Note the instrument matters: with a piano MIDI program the imported values line up with piano numbering and nothing looks wrong. The offset is only apparent on a non-piano (guitar) program.

Link to jsFiddle, CodePen, Project

No response

Version and Environment

[AlphaTab][VersionInfo] alphaTab 1.8.4
[AlphaTab][VersionInfo] commit: 022a45c8e42370f9e12e68949d11eada370da83d
[AlphaTab][VersionInfo] build date: 2026-07-05T14:46:18.224Z
[AlphaTab][VersionInfo] High DPI: 1
[AlphaTab][VersionInfo] Platform: NodeJs
[AlphaTab][VersionInfo] WebPack: false
[AlphaTab][VersionInfo] Vite: false

Also reproduced, with identical output, on the current prerelease:

[AlphaTab][VersionInfo] alphaTab 1.9.0-alpha.1883
[AlphaTab][VersionInfo] commit: a186437bb3263e5ae3f8fd373aef1fef5ebbc7e7
[AlphaTab][VersionInfo] build date: 2026-08-02T03:44:59.527Z
[AlphaTab][VersionInfo] High DPI: 1
[AlphaTab][VersionInfo] Platform: NodeJs
[AlphaTab][VersionInfo] WebPack: false
[AlphaTab][VersionInfo] Vite: false

Node.js v22.23.2, macOS 15 (Darwin 24.6.0).

The rendering symptom was originally noticed in a browser, in an application that displays MuseScore exports. The reproduction above is the reduced Node case; I have not captured printEnvironmentInfo() from that browser session, so I am not quoting browser details I did not record.

Platform

Node.js

Anything else?

Minimal reproducible example. Measure 1 carries <fingering> 1–4; measure 2 carries the equivalent <pluck> values p/i/m/a for comparison.

fingering-offset.musicxml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 4.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="4.0">
  <part-list>
    <score-part id="P1">
      <part-name>Classical Guitar</part-name>
      <score-instrument id="P1-I1">
        <instrument-name>Classical Guitar</instrument-name>
      </score-instrument>
      <midi-instrument id="P1-I1">
        <midi-channel>1</midi-channel>
        <midi-program>25</midi-program>
      </midi-instrument>
    </score-part>
  </part-list>
  <part id="P1">
    <measure number="1">
      <attributes>
        <divisions>1</divisions>
        <key><fifths>0</fifths></key>
        <time><beats>4</beats><beat-type>4</beat-type></time>
        <clef><sign>G</sign><line>2</line><clef-octave-change>-1</clef-octave-change></clef>
      </attributes>
      <note>
        <pitch><step>F</step><alter>1</alter><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><fingering>1</fingering></technical></notations>
      </note>
      <note>
        <pitch><step>G</step><alter>1</alter><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><fingering>2</fingering></technical></notations>
      </note>
      <note>
        <pitch><step>A</step><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><fingering>3</fingering></technical></notations>
      </note>
      <note>
        <pitch><step>B</step><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><fingering>4</fingering></technical></notations>
      </note>
    </measure>
    <!-- Measure 2: the same four fingers written as right-hand <pluck>, for
         comparison. These import correctly. -->
    <measure number="2">
      <note>
        <pitch><step>F</step><alter>1</alter><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><pluck>p</pluck></technical></notations>
      </note>
      <note>
        <pitch><step>G</step><alter>1</alter><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><pluck>i</pluck></technical></notations>
      </note>
      <note>
        <pitch><step>A</step><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><pluck>m</pluck></technical></notations>
      </note>
      <note>
        <pitch><step>B</step><octave>4</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><technical><pluck>a</pluck></technical></notations>
      </note>
    </measure>
  </part>
</score-partwise>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Area

    None yet

    Platform

    None yet

    Work State

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions