镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Slur bezier-x/y from start element gets overwritten by stop element's values #2019

Open

Description

@adam1xz

When a slur has bezier control points on both its start and stop elements in MusicXML, parsing only keeps the stop element's values, the start element's bezier-x/bezier-y get silently overwritten instead of landing in the (separately named) bezierX2/bezierY2 slots.

Repro:

import music21

xml = '''<?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>Music</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>G</sign><line>2</line></clef>
      </attributes>
      <note>
        <pitch><step>C</step><octave>5</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><slur number="1" type="start" bezier-x="11" bezier-y="-22"/></notations>
      </note>
      <note>
        <pitch><step>D</step><octave>5</octave></pitch>
        <duration>1</duration><type>quarter</type>
        <notations><slur number="1" type="stop" bezier-x="-33" bezier-y="44"/></notations>
      </note>
    </measure>
  </part>
</score-partwise>'''

slur = music21.converter.parse(xml, format="musicxml").recurse().getElementsByClass(music21.spanner.Slur)[0]
print(slur.style.bezierX, slur.style.bezierY)  # -33 44 -- should be 11 -22, the START tag's own values

Looks like it's coming from xmlNotationsToSpanners in musicxml/xmlToM21.py, it calls setStyleAttributes once per element found, writing into bezierX/bezierY regardless of whether the element is the start or the stop tag, so whichever one gets processed second wins. The bezier-x2/bezier-y2 attribute names exist and would land in the right slot, but nothing ever routes the stop element's own bezier attributes there.

Activity

  1. mscuthbert commented on Aug 31, 2026

    @mscuthbert
    Member

    Great description -- yes, that would be a good improvement. (attributes are bezierX2 and bezierY2 not -x2 -y2, just in case anyone else is looking)

  2. bingliscodes commented on Oct 6, 2026

    @bingliscodes
    Contributor

    I'd like to take this one, assuming it's still available!

  3. bingliscodes commented on Oct 7, 2026

    @bingliscodes
    Contributor

    I want to clarify something before I go (further) down a rabbit hole.

    The MusicXML schema (musicxml.xsd) bezier attribute group states:

    The attributes bezier-offset2, bezier-x2, and bezier-y2 are only valid with slurs of type continue, and describe the outgoing bezier point

    In the export module (m21ToXml.py), the first Slur gets all the style attributes and type set to start, while the last is just type set to stop. There's even the comment: do not put a notation on mid-slur notes, which would be the continue's

    Are the -X2 and -Y2 intended to be used for the stop coordinates?

    I could fix the import bug by having the end and continue slurs not overwrite the attributes, but this raises questions about the scope of the issue and the value of implementing the full musicXML behavior. That would require someone more familiar with the project to evaluate.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions