From a2bd97aeea0f26cdda0bbc783ca7a7a79eaef2ba Mon Sep 17 00:00:00 2001 From: LeahLegion Date: Thu, 4 Jun 2026 16:44:43 -0700 Subject: [PATCH 1/2] Suppress spurious tuplet bracket on between-note tremolo round-trip. A time-modification with no matching tuplet was importing with a visible tuplet bracket and number, which has been fixed by setting the bracket and number not to show. Fixes #1907 --- music21/musicxml/test_xmlToM21.py | 28 ++++++++++++++++++++++++++++ music21/musicxml/xmlToM21.py | 3 +++ 2 files changed, 31 insertions(+) diff --git a/music21/musicxml/test_xmlToM21.py b/music21/musicxml/test_xmlToM21.py index 954b99a0a..726f9a80d 100644 --- a/music21/musicxml/test_xmlToM21.py +++ b/music21/musicxml/test_xmlToM21.py @@ -1080,6 +1080,34 @@ def testImpliedTuplet(self): tuplets = [n.duration.tuplets[0] for n in s.recurse().notes] self.assertEqual([tup.bracket for tup in tuplets], [True, True, True, False, False, False]) + def testTremoloImpliedTuplet(self): + ''' + Test that between-note tremolos with time-modification of 2:1 do not get tuplets with show-number None, as they should not be drawn as tuplets. + ''' + from music21 import converter + + mxString = ''' + + P + + 256 + + F4 + E3 + 5121whole + 21 + 4 + G3 + 5121whole + 21 + 4 + ''' + + s = converter.parse(mxString, format='musicxml') + tuplets = [n.duration.tuplets[0] for n in s.recurse().notes] + self.assertEqual([tup.bracket for tup in tuplets], [False, False]) + self.assertEqual([tup.tupletActualShow for tup in tuplets], [None, None]) + def test34MeasureRestWithoutTag(self): from xml.etree.ElementTree import fromstring as EL diff --git a/music21/musicxml/xmlToM21.py b/music21/musicxml/xmlToM21.py index 00f2fba35..9c8bad276 100644 --- a/music21/musicxml/xmlToM21.py +++ b/music21/musicxml/xmlToM21.py @@ -4833,6 +4833,9 @@ def xmlToTuplets(self, mxNote: ET.Element) -> list[duration.Tuplet]: remainderFraction.numerator) remainderTuplet.durationNormal = timeModTup.durationNormal remainderTuplet.durationActual = timeModTup.durationActual + remainderTuplet.bracket = False + remainderTuplet.tupletActualShow = None + remainderTuplet.tupletNormalShow = None returnTuplets[-1] = remainderTuplet # now we can remove stops for future notes. From 250d1a48a8b6948de2c6743303cabcef134bd6fd Mon Sep 17 00:00:00 2001 From: LeahLegion Date: Thu, 4 Jun 2026 17:07:43 -0700 Subject: [PATCH 2/2] Fixed formatter and linter errors from too-long dosctring --- music21/musicxml/test_xmlToM21.py | 77 ++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/music21/musicxml/test_xmlToM21.py b/music21/musicxml/test_xmlToM21.py index 726f9a80d..b2743f632 100644 --- a/music21/musicxml/test_xmlToM21.py +++ b/music21/musicxml/test_xmlToM21.py @@ -1082,26 +1082,71 @@ def testImpliedTuplet(self): def testTremoloImpliedTuplet(self): ''' - Test that between-note tremolos with time-modification of 2:1 do not get tuplets with show-number None, as they should not be drawn as tuplets. + Test that between-note tremolos with time-modification of 2:1 do not + get tuplets with show-number None, as they should not be drawn as + tuplets. ''' from music21 import converter mxString = ''' - - P - - 256 - - F4 - E3 - 5121whole - 21 - 4 - G3 - 5121whole - 21 - 4 - ''' + + + + P + + + + + + 256 + + + F + 4 + + + + + E + 3 + + 512 + 1 + whole + + 2 + 1 + + + + 4 + + + + + + G + 3 + + 512 + 1 + whole + + 2 + 1 + + + + 4 + + + + + + ''' s = converter.parse(mxString, format='musicxml') tuplets = [n.duration.tuplets[0] for n in s.recurse().notes]