Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion music21/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
'''
from __future__ import annotations

__version__ = '9.7.1'
__version__ = '9.7.2a4'

def get_version_tuple(vv):
v = vv.split('.')
Expand Down
2 changes: 1 addition & 1 deletion music21/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<class 'music21.base.Music21Object'>

>>> music21.VERSION_STR
'9.7.1'
'9.7.2a4'

Alternatively, after doing a complete import, these classes are available
under the module "base":
Expand Down
3 changes: 2 additions & 1 deletion music21/musicxml/m21ToXml.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from music21 import chord
from music21 import common
from music21.common.enums import AppendSpanners
from music21.common.numberTools import opFrac
from music21 import defaults
from music21 import duration
from music21 import dynamics
Expand Down Expand Up @@ -3322,7 +3323,7 @@ def parseFlatElements(
else:
# if necessary, jump to end of the measure.
if self.offsetInMeasure < firstPassEndOffsetInMeasure:
self.moveForward(firstPassEndOffsetInMeasure)
self.moveForward(opFrac(firstPassEndOffsetInMeasure - self.offsetInMeasure))
Copy link
Member

Choose a reason for hiding this comment

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

Is this part of the same bug fix or a separate bug fix -- it doesn't seem to have anything to do with complex or not complex types? Thus is it actually being tested by the new tests below? I don't think so, so please test it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unrelated. I'll try to write a test for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the record: this is a bug I introduced back when I was implementing SpannerAnchors in the first place. I assumed the wrong thing about what offset should be passed to moveForward. The end result was that MusicXML write from SpannerAnchor-y scores was pretty busted. And I only noticed now because we're making SpannerAnchors now during MusicXML read, so the bug is triggered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Still working on this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just pushed this new test.


self.currentVoiceId = None

Expand Down
54 changes: 54 additions & 0 deletions music21/musicxml/test_m21ToXml.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,60 @@ def test_instrumentDoesNotCreateForward(self):
self.assertTrue(tree.findall('.//note'))
self.assertFalse(tree.findall('.//forward'))

def test_writeFromSpannerAnchorsGetsMeasureEndOffsetRight(self):
'''
Write to MusicXML from a Measure containing SpannerAnchors was not positioning
the current time offset correctly before starting the next written measure.
Now the next measure is positioned at the correct offset.
'''
m1 = stream.Measure()
m1.append(note.Note())
m1.append(note.Note())
m1.append(note.Note())
m1.append(note.Note())
cresc = dynamics.Crescendo()
startAnchor = spanner.SpannerAnchor()
endAnchor = spanner.SpannerAnchor()
m1.insert(0.5, startAnchor)
m1.insert(1.5, endAnchor)
cresc.addSpannedElements(startAnchor, endAnchor)
m1.append(cresc)
p = stream.Part()
p.append(m1)
s = stream.Score()
s.append(p)
# write to MusicXML
tree = self.getET(s)

# walk all the durations (notes, forwards, backups) and make sure they add up
# to where the end of the measure should be (4.0ql)
measEl = None
divisionsEl = None
for el in tree.iter():
if el.tag == 'measure':
measEl = el
for el in measEl.iter():
if el.tag == 'divisions':
divisionsEl = el
break
break

self.assertIsNotNone(measEl)
self.assertIsNotNone(divisionsEl)

divisionsInt = int(divisionsEl.text)
currOffsetQL = 0.
for el in measEl.findall('*'):
dur = el.find('duration')
if dur is not None:
durInt = int(dur.text)
durQL = common.opFrac(fractions.Fraction(durInt, divisionsInt))
if el.tag == 'backup':
currOffsetQL = common.opFrac(currOffsetQL - durQL)
else:
currOffsetQL = common.opFrac(currOffsetQL + durQL)
self.assertEqual(currOffsetQL, 4.)

def testOutOfBoundsExpressionDoesNotCreateForward(self):
'''
A metronome mark at an offset exceeding the bar duration was causing
Expand Down