Repository: cuthbertLab/music21
Pull request #1068 (2021-07-23 15:40:46)

Set paddingRight on MusicXML import and fix beaming of quarter + eighth in final incomplete 6/8 measure
- Set paddingRight on musicXML import
- `makeBeams()` now observes a difference between paddingLeft and paddingRight instead of treating all incomplete measures as having paddingLeft
- `getBeams()` for 6/8 fixed to handle quarter + eighth + eighth:
  - should be None, None, None
  - was None, 'start', 'stop' if incompleteness programmatically interpreted as paddingLeft (see above)
  - was None, None, 'stop' once above issue was fixed

coveralls: 
[![Coverage Status](https://coveralls.io/builds/41609031/badge)](https://coveralls.io/builds/41609031)

Coverage increased (+0.009%) to 92.353% when pulling **ed91de35868a5f825358009cf98a14fde271e64a on jacobtylerwalls:make-beams-paddingRight** into **5d566a8089fdc50b3053d9071a24b9db157a31d4 on cuthbertLab:master**.


Patch:
diff --git a/music21/_version.py b/music21/_version.py
index 7651c8d0c..b4949ae8b 100644
--- a/music21/_version.py
+++ b/music21/_version.py
@@ -42,7 +42,7 @@ When changing, update the single test case in base.py.
 Changing this number invalidates old pickles -- do it if the old pickles create a problem.
 '''
 
-__version_info__ = (7, 0, 7, 'b1')  # can be 4-tuple: (7, 0, 5, 'a2')
+__version_info__ = (7, 0, 8)  # can be 4-tuple: (7, 0, 5, 'a2')
 
 v = '.'.join(str(x) for x in __version_info__[0:3])
 if len(__version_info__) > 3 and __version_info__[3]:
diff --git a/music21/base.py b/music21/base.py
index 3330d787c..1c930b143 100644
--- a/music21/base.py
+++ b/music21/base.py
@@ -28,7 +28,7 @@ available after importing `music21`.
 <class 'music21.base.Music21Object'>
 
 >>> music21.VERSION_STR
-'7.0.7b1'
+'7.0.8'
 
 Alternatively, after doing a complete import, these classes are available
 under the module "base":
diff --git a/music21/meter/base.py b/music21/meter/base.py
index 98d4d016f..ef4ac52c6 100644
--- a/music21/meter/base.py
+++ b/music21/meter/base.py
@@ -1293,6 +1293,14 @@ class TimeSignature(base.Music21Object):
          <music21.beam.Beams <music21.beam.Beam 1/continue>>,
          <music21.beam.Beams <music21.beam.Beam 1/continue>>,
          <music21.beam.Beams <music21.beam.Beam 1/stop>>]
+
+        Fixed in v.7 -- incomplete final measures in 6/8:
+
+        >>> sixEight = meter.TimeSignature('6/8')
+        >>> nList = [note.Note(type='quarter'), note.Note(type='eighth'), note.Note(type='eighth')]
+        >>> beamList = sixEight.getBeams(nList)
+        >>> print(beamList)
+        [None, None, None]
         '''
         from music21 import stream
         if isinstance(srcList, stream.Stream):
@@ -1352,8 +1360,11 @@ class TimeSignature(base.Music21Object):
 
             # watch for a special case where a duration completely fills
             # the archetype; this generally should not be beamed
-            if (start == archetypeSpanStart
-                    and end == archetypeSpanEnd):
+            # same if beamPrevious is None and beamNumber == 1 (quarter-eighth in 6/8)
+            if end == archetypeSpanEnd and (
+                start == archetypeSpanStart
+                or (beamPrevious is None and beamNumber == 1)
+            ):
                 # increment position and continue loop
                 beamsList[i] = None  # replace with None!
                 return
@@ -1368,7 +1379,7 @@ class TimeSignature(base.Music21Object):
 
             elif isLast:  # last is always stop
                 beamType = 'stop'
-                # get a partial beam if we cannot come form a beam
+                # get a partial beam if we cannot form a beam
                 if (beamPrevious is None
                         or beamNumber not in beamPrevious.getNumbers()):
                     # environLocal.warn(['triggering partial left where a stop normally falls'])
diff --git a/music21/musicxml/xmlToM21.py b/music21/musicxml/xmlToM21.py
index f84960122..050e8e405 100644
--- a/music21/musicxml/xmlToM21.py
+++ b/music21/musicxml/xmlToM21.py
@@ -1989,8 +1989,8 @@ class PartParser(XMLParserBase):
         Fills an empty measure with a measure of rest (bug in PDFtoMusic and
         other MusicXML writers).
 
-        sets self.lastMeasureWasShort to True or False if it is an incomplete measure
-        that is not a pickup.
+        Sets self.lastMeasureWasShort to True or False if it is an incomplete measure
+        that is not a pickup and sets paddingRight.
 
         >>> m = stream.Measure([meter.TimeSignature('4/4'), harmony.ChordSymbol('C7')])
         >>> m.highestTime
@@ -2002,6 +2002,17 @@ class PartParser(XMLParserBase):
         4.0
         >>> PP.lastMeasureWasShort
         False
+
+        Incomplete final measure:
+
+        >>> m = stream.Measure([meter.TimeSignature('6/8'), note.Note(), note.Note()])
+        >>> m.offset = 24.0
+        >>> PP = musicxml.xmlToM21.PartParser()
+        >>> PP.lastMeasureOffset = 21.0
+        >>> PP.setLastMeasureInfo(m)
+        >>> PP.adjustTimeAttributesFromMeasure(m)
+        >>> m.paddingRight
+        1.0
         '''
         # note: we cannot assume that the time signature properly
         # describes the offsets w/n this bar. need to look at
@@ -2049,6 +2060,9 @@ class PartParser(XMLParserBase):
                         # or something
                         self.lastMeasureWasShort = False
                 else:
+                    # Incomplete measure that is likely NOT an anacrusis, set paddingRight
+                    if m.barDurationProportion() < 1.0:
+                        m.paddingRight = m.barDuration.quarterLength - m.highestTime
                     if mHighestTime < lastTimeSignatureQuarterLength:
                         self.lastMeasureWasShort = True
                     else:
diff --git a/music21/stream/makeNotation.py b/music21/stream/makeNotation.py
index f1a71b5e2..0efa83ce6 100644
--- a/music21/stream/makeNotation.py
+++ b/music21/stream/makeNotation.py
@@ -188,6 +188,9 @@ def makeBeams(
             offset = 0.0
             if m.paddingLeft != 0.0:
                 offset = opFrac(m.paddingLeft)
+            elif m.paddingRight != 0.0:
+                pass
+            # Incomplete measure without any padding set: assume paddingLeft
             elif noteStream.highestTime < barQL:
                 offset = barQL - noteStream.highestTime
 


Test patch:
diff --git a/music21/stream/tests.py b/music21/stream/tests.py
index 58eb22af6..5b763f437 100644
--- a/music21/stream/tests.py
+++ b/music21/stream/tests.py
@@ -8303,6 +8303,33 @@ class Test(unittest.TestCase):
         self.assertEqual(beams[3], continue_beam)  # fourth should be continue
         self.assertEqual(beams[4], stop_beam)  # last should be stop
 
+    def test_makeBeams__paddingRight(self):
+        m = Measure()
+        m.timeSignature = meter.TimeSignature('6/8')
+        m.paddingRight = 1.0
+        m.append(note.Note(type='quarter'))
+        m.append(note.Note(type='eighth'))
+        m.append(note.Note(type='eighth'))
+
+        m.makeBeams(inPlace=True)
+        beams = self.get_beams_from_stream(m)
+
+        no_beam = beam.Beams()
+        start_beam = beam.Beams()
+        start_beam.append('start')
+        stop_beam = beam.Beams()
+        stop_beam.append('stop')
+
+        self.assertEqual(beams, [no_beam, no_beam, no_beam])
+
+        m.paddingRight = 0.5
+        m.append(note.Note(type='eighth'))
+
+        m.makeBeams(inPlace=True)
+        beams = self.get_beams_from_stream(m)
+
+        self.assertEqual(beams, [no_beam, no_beam, start_beam, stop_beam])
+
     def testWrite(self):
         import os