Skip to content

MusicXML: <notehead>x</notehead> is not imported as a dead note — the tab shows the fret and the note sounds unmuted #2866

Description

@ppisljar

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.

A note written as a dead (muted) note in MusicXML — <notehead>x</notehead> on a tablature staff — is imported as an ordinary fretted note.

Two things a user notices:

  • On screen, the tab staff shows the fret number where an x is expected. The note is indistinguishable from the un-muted note next to it.
  • In playback, it sounds as a normal sustained note instead of the short muted click a dead note makes.

The same music written in alphaTex with {x} gives both the x in the tab and the short muted sound, so this looks specific to the MusicXML side rather than to how dead notes work generally.

Rendering the two-note example below (one plain note, one with <notehead>x</notehead>, same string and fret) and reading the text out of the produced SVG gives the tab digits, and generating the MIDI gives the note lengths:

source tab shows MIDI note lengths (ticks)
MusicXML, 2nd note has <notehead>x</notehead> 2, 2 960, 960
alphaTex :4 2.3 2.3{x} (same pitch) 2, x 960, 60

Both produce MIDI key 57 for both notes, so the only difference is that the MusicXML note is neither drawn nor sounded as muted.

Expected Behavior

A note carrying <notehead>x</notehead> should be imported as a dead/muted note: the tablature staff should show x instead of the fret number, and playback should produce the short muted sound — matching what alphaTex {x} and Guitar Pro dead notes already do.

x is the standard MusicXML notehead for muted/dead notes on guitar, and it is what MuseScore, Guitar Pro and Sibelius all export for them.

The MusicXML support matrix lists noteheadx as ✅ Supported for Model, Reading, Render, Audio and Tex, which is why I am reporting this as a bug rather than asking for a new feature.

Steps To Reproduce

  1. Load the MusicXML below — two quarter notes on the same string and fret, the second one carrying <notehead>x</notehead>.
  2. Render it with the tab stave profile and look at the tab digits, and generate the MIDI and look at the note lengths.
  3. Observe that the second note is drawn with its fret number and lasts as long as the first, instead of being drawn as x and cut short.
import * as alphaTab from '@coderline/alphatab';

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<score-partwise version="4.0">
  <part-list><score-part id="P1"><part-name>Guitar</part-name></score-part></part-list>
  <part id="P1"><measure number="1">
    <attributes>
      <divisions>1</divisions><time><beats>2</beats><beat-type>4</beat-type></time>
      <clef><sign>TAB</sign><line>5</line></clef>
      <staff-details><staff-lines>6</staff-lines>
        <staff-tuning line="1"><tuning-step>E</tuning-step><tuning-octave>2</tuning-octave></staff-tuning>
        <staff-tuning line="2"><tuning-step>A</tuning-step><tuning-octave>2</tuning-octave></staff-tuning>
        <staff-tuning line="3"><tuning-step>D</tuning-step><tuning-octave>3</tuning-octave></staff-tuning>
        <staff-tuning line="4"><tuning-step>G</tuning-step><tuning-octave>3</tuning-octave></staff-tuning>
        <staff-tuning line="5"><tuning-step>B</tuning-step><tuning-octave>3</tuning-octave></staff-tuning>
        <staff-tuning line="6"><tuning-step>E</tuning-step><tuning-octave>4</tuning-octave></staff-tuning>
      </staff-details>
    </attributes>
    <note>
      <pitch><step>A</step><octave>3</octave></pitch>
      <duration>1</duration><voice>1</voice><type>quarter</type>
      <notations><technical><string>3</string><fret>2</fret></technical></notations>
    </note>
    <note>
      <pitch><step>A</step><octave>3</octave></pitch>
      <duration>1</duration><voice>1</voice><type>quarter</type>
      <notehead>x</notehead>
      <notations><technical><string>3</string><fret>2</fret></technical></notations>
    </note>
  </measure></part>
</score-partwise>`;

function tabDigits(score) {
  const settings = new alphaTab.Settings();
  settings.core.engine = 'svg';
  settings.core.enableLazyLoading = false;
  settings.display.staveProfile = alphaTab.StaveProfile.Tab;
  const renderer = new alphaTab.rendering.ScoreRenderer(settings);
  renderer.width = 900;
  let svg = '';
  renderer.partialRenderFinished.on(r => { svg += r.renderResult; });
  renderer.renderScore(score, [0]);
  return [...svg.matchAll(/>([^<>]{1,3})<\/text>/g)].map(m => m[1].trim()).filter(t => t);
}

function midiNotes(score) {
  const midi = new alphaTab.midi.MidiFile();
  new alphaTab.midi.MidiFileGenerator(score, new alphaTab.Settings(),
    new alphaTab.midi.AlphaSynthMidiFileHandler(midi)).generate();
  const on = new Map(), out = [];
  for (const e of midi.events) {
    if (e.type === alphaTab.midi.MidiEventType.NoteOn) on.set(e.noteKey, e.tick);
    else if (e.type === alphaTab.midi.MidiEventType.NoteOff && on.has(e.noteKey)) {
      out.push({ key: e.noteKey, dur: e.tick - on.get(e.noteKey) });
      on.delete(e.noteKey);
    }
  }
  return out;
}

const fromXml = alphaTab.importer.ScoreLoader.loadScoreFromBytes(new TextEncoder().encode(xml));
const fromTex = alphaTab.importer.ScoreLoader.loadAlphaTex(
  '\\tuning E4 B3 G3 D3 A2 E2 . :4 2.3 2.3{x}');

console.log('MusicXML tab :', tabDigits(fromXml), midiNotes(fromXml));
console.log('alphaTex tab :', tabDigits(fromTex), midiNotes(fromTex));

Output on 1.8.4:

MusicXML tab : [ '1', '2', '2' ] [ { key: 57, dur: 960 }, { key: 57, dur: 960 } ]
alphaTex tab : [ '1', '2', 'x' ] [ { key: 57, dur: 960 }, { key: 57, dur: 60 } ]

(the leading 1 is the bar number)

Link to jsFiddle, CodePen, Project

No hosted example — the snippet above is self-contained and needs no score file.

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

Node.js v22.20.0, macOS 15.6.1 (Darwin 24.6.0)

The above is the real printEnvironmentInfo() output from the environment where the snippet was run.

Platform

Node.js (where the reproduction above was run and verified)

Anything else?

Where this showed up in practice: I generate MusicXML from guitar tabs and read it back with alphaTab. Dead notes are very common in that material — in one 10-song set, 777 of the notes are dead notes, and all of them come back as ordinary fretted notes, which changes both how the tab reads and how it sounds.

<notehead>x</notehead> also appears on percussion staves, where it is the normal notehead for cymbals and hi-hats rather than a muted note, so the two cases are worth keeping apart.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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