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
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()
def getDynamicWedgeString(self) -> str: if not self.isDynamicWedgeStartOrStop: return '' return M21Convert.getDynamicWedgeString(self.m21Object, self.isDynamicWedgeStart, self.isDynamicWedgeStop)
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)
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()