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

Labels

No labels
No labels

Type

Fields

Priority

Low

Effort

Low

Area

File Formats

Platform

All / Multiple

Work State

Accepted

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions