def test_DateBetween():
    # a few straightforward examples (using both '-' and '^'), then some malformed ones (e.g.
    # 3 dates instead of two, or two dates, one of which is malformed, or 1 date)
    string = '1979/06/01/17:03:56-1979/06/30/17:03:56'  # June 1-30, 1979 (timestamps equal)
    dateBetween = M21Convert.m21DateObjectFromString(string)
    CheckM21DateBetween(dateBetween,
                        expectedYear=1979,
                        expectedMonth=6,
                        expectedDay=(1, 30),
                        expectedHour=17,
                        expectedMinute=3,
                        expectedSecond=56)
    newString: str = M21Convert.stringFromM21DateObject(dateBetween)
    CheckString(newString, expectedString=string)

    string = '1979/06/01/17:03:56^1979/06/30/17:03:56'  # June 1-30, 1979 (timestamps equal)
    dateBetween = M21Convert.m21DateObjectFromString(string)
    CheckM21DateBetween(dateBetween,
                        expectedYear=1979,
                        expectedMonth=6,
                        expectedDay=(1, 30),
                        expectedHour=17,
                        expectedMinute=3,
                        expectedSecond=56)
    newString: str = M21Convert.stringFromM21DateObject(dateBetween)
    CheckString(
        newString,
        expectedString='1979/06/01/17:03:56-1979/06/30/17:03:56')  # ^ -> -

    # this one has a backward range.  Apparently no-one cares...
    string = '1979/06/30/17:03:56-1979/06/01/17:03:56'  # June 30-1, 1979 (timestamps equal)
    dateBetween = M21Convert.m21DateObjectFromString(string)
    CheckM21DateBetween(dateBetween,
                        expectedYear=1979,
                        expectedMonth=6,
                        expectedDay=(30, 1),
                        expectedHour=17,
                        expectedMinute=3,
                        expectedSecond=56)
    newString: str = M21Convert.stringFromM21DateObject(dateBetween)
    CheckString(newString, expectedString=string)

    # very simple example
    string = '1942-1943'
    dateBetween = M21Convert.m21DateObjectFromString(string)
    CheckM21DateBetween(dateBetween, expectedYear=(1942, 1943))
    newString: str = M21Convert.stringFromM21DateObject(dateBetween)
    CheckString(newString, expectedString=string)

    # very simple bad example (3 dates)
    string = '1942-1943-1944'
    dateBetween = M21Convert.m21DateObjectFromString(string)
    assert dateBetween is None  # should fail because '1943-1944' can't parse as a year number

    # very simple bad example (1 date)
    string = '1942-'
    dateBetween = M21Convert.m21DateObjectFromString(string)
    assert dateBetween is None  # should fail because '' has no numeric date fields in it
Example #2
0
    def _parseMeasure(self):
        self._setStartTimeOfMeasure()
        self._duration = HumNum(self.m21Measure.duration.quarterLength)

        # m21 tracks timesigdur for us in barDuration, which is always the latest timeSig duration
        # But it can be ridiculously slow if it has to search back in the score for a timesignature,
        # so we only call it if the measure has a timesignature. If it doesn't have one, we
        # just use the _timeSigDur of the previous measure.
        if self.m21Measure.timeSignature is None and self._prevMeasData is not None:
            self._timeSigDur = self._prevMeasData.timeSigDur
        else:
            self._timeSigDur = HumNum(self.m21Measure.barDuration.quarterLength)

        self._measureNumberString = self.m21Measure.measureNumberWithSuffix()
        if self._measureNumberString == '0':
            self._measureNumberString = ''

        # In humdrum, measure style is a combination of this measure's left barline and the
        # previous measure's right barline.  (For example, ':|!|:' in a humdrum barline comes
        # from the previous right barline being an end-repeat (light-heavy) and the current
        # left barline being a start repeat (heavy-light)).
        # The very last humdrum barline (last measure's right barline) is handled as a special
        # case at a higher level, not here.

        # Compute our left and right barline style
        self.leftBarlineStyle = M21Convert.measureStyleFromM21Barline(self.m21Measure.leftBarline)
        self.rightBarlineStyle = M21Convert.measureStyleFromM21Barline(self.m21Measure.rightBarline)

        # Grab the previous measure's right barline style (if there is one) and
        # combine it with our left barline style, giving our measureStyle.
        prevRightMeasureStyle: MeasureStyle = MeasureStyle.Regular
        if self._prevMeasData is not None:
            prevRightMeasureStyle = self._prevMeasData.rightBarlineStyle
        self.measureStyle = M21Convert.combineTwoMeasureStyles(self.leftBarlineStyle,
                                                               prevRightMeasureStyle)

        # measure index 0 only: add events for any Instruments found in ownerStaff.m21PartStaff
        if self.measureIndex == 0:
            for elementIndex, inst in enumerate(
                    self.ownerStaff.m21PartStaff.getElementsByClass(m21.instrument.Instrument)):
                event: EventData = EventData(inst, elementIndex, -1, self)
                if event is not None:
                    self.events.append(event)

        if len(list(self.m21Measure.voices)) == 0:
            # treat the measure itself as voice 0
            self._parseEventsIn(self.m21Measure, 0)
        else:
            # parse the 0-offset non-streams first...
            self._parseEventsAtTopLevelOf(self.m21Measure)
            # ... then parse the voices
            for voiceIndex, voice in enumerate(self.m21Measure.voices):
                emptyStartDuration: HumNum = HumNum(voice.offset)
                emptyEndDuration: HumNum = HumNum(self.duration - (HumNum(voice.offset) + HumNum(voice.duration.quarterLength)))
                self._parseEventsIn(voice, voiceIndex, emptyStartDuration, emptyEndDuration)

        self._sortEvents()
Example #3
0
    def getDynamicWedgeString(self) -> str:
        if not self.isDynamicWedgeStartOrStop:
            return ''

        return M21Convert.getDynamicWedgeString(self.m21Object,
                                                self.isDynamicWedgeStart,
                                                self.isDynamicWedgeStop)
Example #4
0
 def getNoteKernTokenStringAndLayouts(
         self,
         spannerBundle: m21.spanner.SpannerBundle) -> Tuple[str, List[str]]:
     # We pass in self to get reports of the existence of editorial accidentals, ornaments,
     # etc. These reports get passed up the EventData.py/MeasureData.py reporting chain up
     # to PartData.py, where they are stored and/or acted upon.
     return M21Convert.kernTokenStringAndLayoutsFromM21GeneralNote(
         self.m21Object, spannerBundle, self)
Example #5
0
def test_DateSelection():
    # a few straightforward examples, then some malformed ones
    string = '1979/06/01/17:03:56.00|1979/06/30/17:03:56.00' # June 1 or June 30, 1979 (timestamps equal)
    dateSelection = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSelection(dateSelection, expectedNumDates = 2,
                                   expectedYear = 1979,
                                   expectedMonth = 6,
                                   expectedDay = (1, 30),
                                   expectedHour = 17,
                                   expectedMinute = 3,
                                   expectedSecond = 56.0)
    newString: str = M21Convert.stringFromM21DateObject(dateSelection)
    CheckString(newString, expectedString = string)

    # June 1, June 15, or June 30, 1979 (timestamps equal)
    string = '1979/06/01/17:03:56.00|1979/06/15/17:03:56.00|1979/06/30/17:03:56.00'
    dateSelection = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSelection(dateSelection, expectedNumDates = 3,
                                   expectedYear = 1979,
                                   expectedMonth = 6,
                                   expectedDay = (1, 15, 30),
                                   expectedHour = 17,
                                   expectedMinute = 3,
                                   expectedSecond = 56.0)
    newString: str = M21Convert.stringFromM21DateObject(dateSelection)
    CheckString(newString, expectedString = string)

    string = '1940 | @100 | 1765 | @10000 | 1960 | 1961|1978|1979| 1995'
    dateSelection = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSelection(dateSelection, expectedNumDates = 9,
        expectedYear = (1940, -100, 1765, -10000, 1960, 1961, 1978, 1979, 1995) )
    newString: str = M21Convert.stringFromM21DateObject(dateSelection)
    CheckString(newString, expectedString = '1940|@100|1765|@10000|1960|1961|1978|1979|1995') # no spaces
def test_DateRelative():
    # We don't need lots of different date formats here (they're tested in test_DateSingle).
    # Just a few examples of '<' and '>' dates.
    string = '>1979z/06x/01z/17x:03z:59.999x'
    dateRelative = M21Convert.m21DateObjectFromString(string)
    CheckM21DateRelative(dateRelative,
                         expectedYear=1979,
                         expectedMonth=6,
                         expectedDay=1,
                         expectedHour=17,
                         expectedMinute=3,
                         expectedSecond=59,
                         expectedYearError='uncertain',
                         expectedMonthError='approximate',
                         expectedDayError='uncertain',
                         expectedHourError='approximate',
                         expectedMinuteError='uncertain',
                         expectedSecondError='approximate',
                         expectedRelevance='after')
    newString: str = M21Convert.stringFromM21DateObject(dateRelative)
    CheckString(newString, expectedString='>1979z/06x/01z/17x:03z:59x')

    string = '<1979z/06x/01z/17x:03z:59.999x'
    dateRelative = M21Convert.m21DateObjectFromString(string)
    CheckM21DateRelative(dateRelative,
                         expectedYear=1979,
                         expectedMonth=6,
                         expectedDay=1,
                         expectedHour=17,
                         expectedMinute=3,
                         expectedSecond=59,
                         expectedYearError='uncertain',
                         expectedMonthError='approximate',
                         expectedDayError='uncertain',
                         expectedHourError='approximate',
                         expectedMinuteError='uncertain',
                         expectedSecondError='approximate',
                         expectedRelevance='prior')
    newString: str = M21Convert.stringFromM21DateObject(dateRelative)
    CheckString(newString, expectedString='<1979z/06x/01z/17x:03z:59x')

    # Try one with a '<' in the wrong location to make sure it doesn't parse
    string = '1979</06/01/17:03:56'
    dateRelative = M21Convert.m21DateObjectFromString(string)
    assert dateRelative is None

    # Try one with a '>' in the wrong location to make sure it doesn't parse
    string = '1979/06/01/17:03:56>'
    dateRelative = M21Convert.m21DateObjectFromString(string)
    assert dateRelative is None
def test_DateSingle():
    string = '///::.11'  # eleven one-hundredths of a second
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedSecond=0)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='///::'
                )  # truncates the 11 milliseconds, so no seconds at all

    string = 'year/month/day/hour:minutes:.11'  # unparseable (but reasonably well-formed)
    dateSingle = M21Convert.m21DateObjectFromString(string)
    assert dateSingle is None  # no elaborate check needed
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='')

    string = '///::11'  # 11th second
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedSecond=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='///::11')

    string = '///:11'  # 11th minute
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedMinute=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='///:11:')  # adds trailing ':'

    string = '///11'  # 11 o’clock
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedHour=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='///11::')  # adds trailing ':'s

    string = '11'  # the year 11 A.D.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '11/'  # the year 11 A.D.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='11')  # removes trailing '/'s

    string = '11//'  # the year 11 A.D.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='11')  # removes trailing '/'s

    string = '11///'  # the year 11 A.D.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='11')  # removes trailing '/'s

    string = '@11'  # the year 11 B.C.E.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=-11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '@11/'  # the year 11 B.C.E.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=-11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='@11')  # removes trailing '/'

    string = '@11//'  # the year 11 B.C.E.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=-11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='@11')  # removes trailing '/'s

    string = '@11///'  # the year 11 B.C.E.
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=-11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='@11')  # removes trailing '/'s

    string = '/11'  # November
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedMonth=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '//11'  # 11th day of the month
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedDay=11)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    # more normal cases (just date, no time)
    string = '1943'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle, expectedYear=1943)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '1960/3/22'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1960,
                       expectedMonth=3,
                       expectedDay=22)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString,
                expectedString='1960/03/22')  # adds leading 0 to month

    string = '@12345/10/31'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=-12345,
                       expectedMonth=10,
                       expectedDay=31)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    # now with some approximations (~ for the whole date, x for a value within the date)
    # and uncertainty (? for the whole date, z for a value within the date)
    string = '~1979/06/01'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedHour=None,
                       expectedRelevance='approximate')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '1979x/06z/01z'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedYearError='approximate',
                       expectedMonthError='uncertain',
                       expectedDayError='uncertain',
                       expectedRelevance='certain')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '1979x/06z/01y'  # that 'y' is not a valid error symbol
    dateSingle = M21Convert.m21DateObjectFromString(string)
    assert dateSingle is None
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='')

    string = '~1979x/06z/01z'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedYearError='approximate',
                       expectedMonthError='uncertain',
                       expectedDayError='uncertain',
                       expectedRelevance='approximate')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '?1979z/06x/01z'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedYearError='uncertain',
                       expectedMonthError='approximate',
                       expectedDayError='uncertain',
                       expectedRelevance='uncertain')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString=string)

    string = '?1979z/06x/01z/17:03:58.999'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(
        dateSingle,
        expectedYear=1979,
        expectedMonth=6,
        expectedDay=1,
        expectedHour=17,
        expectedMinute=3,
        expectedSecond=58,  # truncated off the 999 milliseconds
        expectedYearError='uncertain',
        expectedMonthError='approximate',
        expectedDayError='uncertain',
        expectedRelevance='uncertain')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='?1979z/06x/01z/17:03:58')

    string = '?1979z/06x/01z/17:03:59.999'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedHour=17,
                       expectedMinute=3,
                       expectedSecond=59,
                       expectedYearError='uncertain',
                       expectedMonthError='approximate',
                       expectedDayError='uncertain',
                       expectedRelevance='uncertain')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='?1979z/06x/01z/17:03:59')

    string = '1979z/06x/01z/17x:03z:59.999x'
    dateSingle = M21Convert.m21DateObjectFromString(string)
    CheckM21DateSingle(dateSingle,
                       expectedYear=1979,
                       expectedMonth=6,
                       expectedDay=1,
                       expectedHour=17,
                       expectedMinute=3,
                       expectedSecond=59,
                       expectedYearError='uncertain',
                       expectedMonthError='approximate',
                       expectedDayError='uncertain',
                       expectedHourError='approximate',
                       expectedMinuteError='uncertain',
                       expectedSecondError='approximate',
                       expectedRelevance='certain')
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='1979z/06x/01z/17x:03z:59x')

    # test a DateSingle object that was created by hand to be problematic for the writer...
    # We have an invalid yearError, which we should ignore, since it has no associated
    # error symbol ('x' for 'approximate' or 'z' for 'uncertain', but nothing at all for
    # 'what-the-even-heck')
    date = m21.metadata.Date(year=1943,
                             month=7,
                             yearError='what-the-even-heck')
    dateSingle = m21.metadata.DateSingle(date)
    newString: str = M21Convert.stringFromM21DateObject(dateSingle)
    CheckString(newString, expectedString='1943/07')
    def _parseMeasure(self) -> None:
        self._setStartTimeOfMeasure()
        self._duration = self.m21Measure.duration.quarterLength

        # m21 tracks timesigdur for us in barDuration, which is always the latest timeSig duration
        # But it can be ridiculously slow if it has to search back in the score for a timesignature,
        # so we only call it if the measure has a timesignature. If it doesn't have one, we
        # just use the _timeSigDur of the previous measure.
        if self.m21Measure.timeSignature is None and self._prevMeasData is not None:
            self._timeSigDur = self._prevMeasData.timeSigDur
        else:
            self._timeSigDur = self.m21Measure.barDuration.quarterLength

        self._measureNumberString = self.m21Measure.measureNumberWithSuffix()
        if self._measureNumberString == '0':
            self._measureNumberString = ''

        # In humdrum, measure style is a combination of this measure's left barline and the
        # previous measure's right barline.  (For example, ':|!|:' in a humdrum barline comes
        # from the previous right barline being an end-repeat (light-heavy) and the current
        # left barline being a start repeat (heavy-light)).
        # The very last humdrum barline (last measure's right barline) is handled as a special
        # case at a higher level, not here.

        # Compute our left and right barline style
        self.leftBarlineStyle = M21Convert.measureStyleFromM21Barline(self.m21Measure.leftBarline)
        self.rightBarlineStyle = M21Convert.measureStyleFromM21Barline(self.m21Measure.rightBarline)

        # Grab the previous measure's right barline style (if there is one) and
        # combine it with our left barline style, giving our measureStyle.
        prevRightMeasureStyle: MeasureStyle = MeasureStyle.Regular
        if self._prevMeasData is not None:
            prevRightMeasureStyle = self._prevMeasData.rightBarlineStyle
        self.measureStyle = M21Convert.combineTwoMeasureStyles(self.leftBarlineStyle,
                                                               prevRightMeasureStyle)
        # Extract left and right barline Fermata
        self.leftBarlineFermataStyle = M21Convert.fermataStyleFromM21Barline(
            self.m21Measure.leftBarline
        )
        self.rightBarlineFermataStyle = M21Convert.fermataStyleFromM21Barline(
            self.m21Measure.rightBarline
        )

        # Grab the previous measure's right barline fermata style (if there is one) and
        # combine it with our left barline fermata style, giving our fermataStyle.
        prevRightBarlineFermataStyle: FermataStyle = FermataStyle.NoFermata
        if self._prevMeasData is not None:
            prevRightBarlineFermataStyle = self._prevMeasData.rightBarlineFermataStyle
        self.fermataStyle = M21Convert.combineTwoFermataStyles(
            self.leftBarlineFermataStyle,
            prevRightBarlineFermataStyle
        )

        # measure index 0 only: add events for any Instruments found in ownerStaff.m21PartStaff
        if self.measureIndex == 0:
            for elementIndex, inst in enumerate(
                    self.ownerStaff.m21PartStaff.getElementsByClass(m21.instrument.Instrument)):
                event: EventData = EventData(inst, elementIndex, -1, self)
                if event is not None:
                    self.events.append(event)

        # parse any RepeatBracket this measure is in.
        for rb in self.m21Measure.getSpannerSites([m21.spanner.RepeatBracket]):
            # measure is in this RepeatBracket
            if t.TYPE_CHECKING:
                assert isinstance(rb, m21.spanner.RepeatBracket)
            self.inRepeatBracket = True
            if rb.overrideDisplay:
                self.repeatBracketName = rb.overrideDisplay
            else:
                self.repeatBracketName = rb.number

            if rb.getFirst() == self.m21Measure:
                # this measure starts the RepeatBracket (it may also stop it)
                self.startsRepeatBracket = True

            if rb.getLast() == self.m21Measure:
                # this measure stops the RepeatBracket (it may also start it)
                self.stopsRepeatBracket = True

            # a measure can only be in one RepeatBracket, so stop looking
            break

        if len(list(self.m21Measure.voices)) == 0:
            # treat the measure itself as voice 0
            self._parseEventsIn(self.m21Measure, 0)
        else:
            # first parse the voices...
            for voiceIndex, voice in enumerate(self.m21Measure.voices):
                emptyStartDuration: HumNum = voice.offset
                emptyEndDuration: HumNum = opFrac(
                    self.duration - (voice.offset + voice.duration.quarterLength)
                )
                self._parseEventsIn(voice, voiceIndex, emptyStartDuration, emptyEndDuration)

            # ... then parse the non-streams last, so that the ending barline lands after
            # any objects in the voices that are also at the last offset in the measure
            # (e.g. TextExpressions after the last note in the measure).
            self._parseEventsAtTopLevelOf(self.m21Measure)

        self._sortEvents()