Skip to content

Fix invalid MusicXML for an unpitched grace note in a voice#1973

Merged
jacobtylerwalls merged 2 commits into
cuthbertLab:masterfrom
pablopupo:fix/1732-unpitched-voice-ordering
Jul 5, 2026
Merged

Fix invalid MusicXML for an unpitched grace note in a voice#1973
jacobtylerwalls merged 2 commits into
cuthbertLab:masterfrom
pablopupo:fix/1732-unpitched-voice-ordering

Conversation

@pablopupo

@pablopupo pablopupo commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #1732. Following up on the September 2024 comment that you'd be glad to take a fix for this one.

An unpitched grace note in a voice exported <voice> ahead of <unpitched>, which fails schema validation, since <unpitched> has to come right after <grace> in the note content model. unpitchedToXml retrofits <unpitched> into the already-built <note> by inserting before the earliest of <duration> or <type>, but a grace note has no <duration>, so anything noteToXml had appended in between slipped ahead. The tagList now lists every element that can follow <unpitched> within <note>, which also fixes the same misplacement for a tied grace note (<tie> landed ahead of <unpitched> too).

Before, from the issue's repro:

<note>
  <grace slash="yes" />
  <voice>1</voice>
  <unpitched>
    <display-step>B</display-step>
    <display-octave>4</display-octave>
  </unpitched>
  <type>eighth</type>
</note>

After:

<note>
  <grace slash="yes" />
  <unpitched>
    <display-step>B</display-step>
    <display-octave>4</display-octave>
  </unpitched>
  <voice>1</voice>
  <type>eighth</type>
</note>

Added a doctest for the voice case, a regression test in test_m21ToXml.py, and bumped the version to 11.0.0b7 for the writer change. pylint (10.00/10), ruff, mypy, and the musicxml module tests all pass locally.

@coveralls

coveralls commented Jul 4, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 93.3% (+0.003%) from 93.297% — pablopupo:fix/1732-unpitched-voice-ordering into cuthbertLab:master

unpitchedToXml inserted <unpitched> before the earliest of <duration> or
<type>, but a grace note has no <duration>, so anything noteToXml had
appended in between (voice, tie, instrument, footnote, level) came out
ahead of <unpitched> and the file failed schema validation. List every
element that can follow <unpitched> within <note> so the insertion point
is right with or without a duration.

Bump version to 11.0.0b7 for the musicxml writer change.

Fixes cuthbertLab#1732.
@pablopupo pablopupo force-pushed the fix/1732-unpitched-voice-ordering branch from 8f651af to c9ffb2a Compare July 4, 2026 21:13
@pablopupo pablopupo changed the title (AI) Fix invalid MusicXML for an unpitched grace note in a voice Fix invalid MusicXML for an unpitched grace note in a voice Jul 4, 2026

@jacobtylerwalls jacobtylerwalls left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR -- One question for your consideration.

Comment thread music21/musicxml/m21ToXml.py Outdated
Only <grace>, <cue>, and <chord> may precede <unpitched> within <note>,
so a new insertAfterElements helper places it after those instead of
maintaining a list of everything that can follow it.

@jacobtylerwalls jacobtylerwalls left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 👍

@jacobtylerwalls jacobtylerwalls merged commit 18fbeb7 into cuthbertLab:master Jul 5, 2026
7 checks passed
@mscuthbert

Copy link
Copy Markdown
Member

Thanks all. This is great!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unpitched grace note in a voice exports a malformed musicxml file

4 participants