Esempio n. 1
0
    def analyzeRhythmOfFloatingSpine(self, spineStart: HumdrumToken) -> bool:
        durSum: HumNum = opFrac(0)
        foundDur: HumNum = opFrac(0)

        # Find a known durationFromStart for a line in the Humdrum file, then
        # use that to calculate the starting duration of the floating spine.
        if spineStart.durationFromStart >= 0:
            foundDur = spineStart.durationFromStart
        else:
            token: t.Optional[HumdrumToken] = spineStart
            while token is not None:
                if token.durationFromStart >= 0:
                    foundDur = token.durationFromStart
                    break
                if token.duration > 0:
                    durSum = opFrac(durSum + token.duration)
                token = token.nextToken0

        if foundDur == 0:
            return self.setParseError(
                'Error: cannot link floating spine to score.')

        success: bool = self.assignDurationsToTrack(spineStart,
                                                    foundDur - durSum)
        if not success:
            return self.isValid

        return self.isValid
Esempio n. 2
0
    def __init__(self, 
                 offsetStart=0.0, 
                 offsetEnd=None, 
                 *,
                 includeEndBoundary=True, 
                 mustFinishInSpan=False,
                 mustBeginInSpan=True, 
                 includeElementsThatEndAtStart=True
                 ):
        super().__init__()

        self.offsetStart = opFrac(offsetStart)
        if offsetEnd is None:
            self.offsetEnd = offsetStart
            self.zeroLengthSearch = True
        else:
            self.offsetEnd = opFrac(offsetEnd)
            if offsetEnd > offsetStart:
                self.zeroLengthSearch = False
            else:
                self.zeroLengthSearch = True

        self.mustFinishInSpan = mustFinishInSpan
        self.mustBeginInSpan = mustBeginInSpan
        self.includeEndBoundary = includeEndBoundary
        self.includeElementsThatEndAtStart = includeElementsThatEndAtStart
Esempio n. 3
0
    def assignRhythmFromRecip(self, spineStart: HumdrumToken) -> bool:
        currTok: t.Optional[HumdrumToken] = spineStart
        while currTok is not None:
            if not currTok.isData:
                currTok = currTok.nextToken0
                continue

            if currTok.isNull:
                # This should not occur in a well-formed **recip spine, but
                # treat as a zero duration.
                currTok = currTok.nextToken0
                continue

            currTok.ownerLine.duration = Convert.recipToDuration(currTok.text)
            currTok = currTok.nextToken0

        # now go back and set the absolute position from the start of the file.
        totalDurSoFar: HumNum = opFrac(0)
        for line in self._lines:
            line.durationFromStart = totalDurSoFar
            if line.duration is None or line.duration < 0:
                line.duration = opFrac(0)
            totalDurSoFar = opFrac(totalDurSoFar + line.duration)

        # Analyze durations to/from barlines:
        success = self.analyzeMeter()
        if not success:
            return False
        success = self.analyzeNonNullDataTokens()
        if not success:
            return False

        return True
Esempio n. 4
0
    def __init__(self,
                 offsetStart=0.0,
                 offsetEnd=None,
                 *,
                 includeEndBoundary=True,
                 mustFinishInSpan=False,
                 mustBeginInSpan=True,
                 includeElementsThatEndAtStart=True
                 ):
        super().__init__()

        self.offsetStart = opFrac(offsetStart)
        if offsetEnd is None:
            self.offsetEnd = offsetStart
            self.zeroLengthSearch = True
        else:
            self.offsetEnd = opFrac(offsetEnd)
            if offsetEnd > offsetStart:
                self.zeroLengthSearch = False
            else:
                self.zeroLengthSearch = True

        self.mustFinishInSpan = mustFinishInSpan
        self.mustBeginInSpan = mustBeginInSpan
        self.includeEndBoundary = includeEndBoundary
        self.includeElementsThatEndAtStart = includeElementsThatEndAtStart
Esempio n. 5
0
    def _createRecipTokenFromDuration(duration: HumNumIn) -> HumdrumToken:
        dur: HumNum = opFrac(duration)
        dur = opFrac(dur / opFrac(4))  # convert to quarter note units

        durFraction: Fraction = Fraction(dur)
        if durFraction.numerator == 0:
            # if the GridSlice is at the end of a measure, the
            # time between the starttime/endtime of the GridSlice should
            # be subtracted from the endtime of the current GridMeasure.
            return HumdrumToken('g')

        if durFraction.numerator == 1:
            return HumdrumToken(str(durFraction.denominator))

        if durFraction.numerator % 3 == 0:
            dotdur: HumNum = dur * opFrac(Fraction(2, 3))
            dotdurFraction: Fraction = Fraction(dotdur)
            if dotdurFraction.numerator == 1:
                return HumdrumToken(str(dotdurFraction.denominator) + '.')

        # try to fit to two dots here

        # try to fit to three dots here

        return HumdrumToken(
            str(durFraction.denominator) + '%' + str(durFraction.numerator))
Esempio n. 6
0
    def __init__(self,
                 element: m21.base.Music21Object,
                 elementIndex: int,
                 voiceIndex: int,
                 ownerMeasure,
                 offsetInScore: t.Optional[HumNumIn] = None,
                 duration: t.Optional[HumNumIn] = None) -> None:
        from converter21.humdrum import MeasureData
        from converter21.humdrum import ScoreData
        self.ownerMeasure: MeasureData = ownerMeasure
        self.spannerBundle: m21.spanner.SpannerBundle = (
            self.ownerMeasure.spannerBundle  # from ownerScore, ultimately
        )
        self._startTime: HumNum = opFrac(-1)
        self._duration: HumNum = opFrac(-1)
        self._voiceIndex: int = voiceIndex
        self._elementIndex: int = elementIndex
        self._element: m21.base.Music21Object = element
        self._elementType: t.Type = type(element)
        self._name: str = ''
        self._texts: t.List[m21.expressions.TextExpression] = []
        self._tempos: t.List[m21.tempo.TempoIndication] = []
        self._dynamics: t.List[t.Union[m21.dynamics.Dynamic,
                                       m21.dynamics.DynamicWedge]] = []
        self._myTextsComputed: bool = False
        self._myDynamicsComputed: bool = False

        self._parseEvent(element, offsetInScore, duration)

        ownerScore: ScoreData = ownerMeasure.ownerStaff.ownerPart.ownerScore
        ownerScore.eventFromM21Object[id(element)] = self
Esempio n. 7
0
    def prepareDurations(self, token: HumdrumToken, state: int,
                         startDur: HumNumIn) -> bool:
        if state != token.rhythmAnalysisState:
            return self.isValid

        token.incrementRhythmAnalysisState()

        durSum: HumNum = opFrac(startDur)

        success = self.setLineDurationFromStart(token, durSum)
        if not success:
            return self.isValid

        if token.duration > 0:
            durSum = opFrac(durSum + token.duration)

        reservoir: t.List[HumdrumToken] = []
        startDurs: t.List[HumNum] = []

        # Assign line durationFromStarts for primary track first
        tcount: int = token.nextTokenCount
        while tcount > 0:
            for i, tok in enumerate(token.nextTokens):
                if i == 0:
                    # we'll deal with token 0 ourselves below
                    continue
                reservoir.append(tok)
                startDurs.append(durSum)

            if t.TYPE_CHECKING:
                # we know here that token.nextTokenCount > 0, so
                # token.nextToken0 is not None
                assert isinstance(token.nextToken0, HumdrumToken)

            token = token.nextToken0
            if state != token.rhythmAnalysisState:
                break

            token.incrementRhythmAnalysisState()
            success = self.setLineDurationFromStart(token, durSum)
            if not success:
                return self.isValid

            if token.duration > 0:
                durSum = opFrac(durSum + token.duration)

            tcount = token.nextTokenCount

        if tcount == 0 and token.isTerminateInterpretation:
            success = self.setLineDurationFromStart(token, durSum)
            if not success:
                return self.isValid

        # Process secondary tracks next:
        newState: int = state
        for i in reversed(range(0, len(reservoir))):
            self.prepareDurations(reservoir[i], newState, startDurs[i])

        return self.isValid
Esempio n. 8
0
 def assignLineDurations(self) -> None:
     for i in range(0, len(self._lines)):
         if i == len(self._lines) - 1:
             self._lines[i].duration = opFrac(0)
         else:
             startDur: HumNum = self._lines[i].durationFromStart
             endDur: HumNum = self._lines[i + 1].durationFromStart
             self._lines[i].duration = opFrac(endDur - startDur)
Esempio n. 9
0
    def analyzeNullLineRhythms(self) -> bool:
        nullLines: t.List[HumdrumLine] = []
        previousLine: t.Optional[HumdrumLine] = None
        nextLine: t.Optional[HumdrumLine] = None

        for line in self._lines:
            if t.TYPE_CHECKING:
                # we know that every element of self._lines is not None
                assert isinstance(line, HumdrumLine)

            if not line.hasSpines:
                continue

            if line.isBarline:
                # We start from scratch in each measure.  This is because, if there is a null data
                # line as the first line in a measure, we don't want it to start halfway from last
                # real note in previous measure to first real note in this measure.  Any such
                # unprocessed null lines will end up inheriting their start time from the first
                # non-null note in this measure, during fillInMissingStartTimes' first loop
                # (backwards) over the lines.
                previousLine = None
                nullLines = []

            if line.isAllRhythmicNull:
                if line.isData:
                    nullLines.append(line)
                continue

            if line.durationFromStart < 0:
                if line.isData:
                    return self.setParseError(
                        'Error: found an unexpectedly missing durationFromStart on '
                        + f'data line {line.durationFromStart}\n' +
                        f'Line: {line.text}')
                continue

            nextLine = line
            if previousLine is None:
                previousLine = nextLine
                nullLines = []
                continue

            if t.TYPE_CHECKING:
                # we know previousLine is not None if we get here
                assert isinstance(previousLine, HumdrumLine)

            startDur: HumNum = previousLine.durationFromStart
            endDur: HumNum = nextLine.durationFromStart
            gapDur: HumNum = opFrac(endDur - startDur)
            nullDur: HumNum = opFrac(gapDur / (len(nullLines) + 1))
            for j, nullLine in enumerate(nullLines):
                nullLine.durationFromStart = opFrac(startDur + opFrac(nullDur *
                                                                      (j + 1)))

            previousLine = nextLine
            nullLines = []

        return self.isValid
Esempio n. 10
0
    def durationToEnd(self) -> HumNum:
        if not self._rhythmAnalyzed:
            if self._ownerFile:
                self._ownerFile.analyzeRhythmStructure()
            else:
                # there's no owner, so we can't get the score duration
                return opFrac(0)

        return opFrac(self._ownerFile.scoreDuration - self.durationFromStart)
Esempio n. 11
0
    def _setStartTimeOfMeasure(self) -> None:
        if self.ownerStaff is None:
            self._startTime = opFrac(0)
            return

        if self._prevMeasData is None:
            self._startTime = opFrac(0)
            return

        self._startTime = opFrac(self._prevMeasData.startTime + self._prevMeasData.duration)
Esempio n. 12
0
    def _parseEventsIn(
            self,
            m21Stream: t.Union[m21.stream.Voice, m21.stream.Measure],
            voiceIndex: int,
            emptyStartDuration: HumNumIn = 0,
            emptyEndDuration: HumNumIn = 0
    ) -> None:
        event: EventData
        durations: t.List[HumNum]
        startTime: HumNum
        if emptyStartDuration > 0:
            # make m21 hidden rests totalling this duration, and pretend they
            # were at the beginning of m21Stream
            durations = Convert.getPowerOfTwoDurationsWithDotsAddingTo(emptyStartDuration)
            startTime = self.startTime
            for duration in durations:
                m21StartRest: m21.note.Rest = m21.note.Rest(
                    duration=m21.duration.Duration(duration)
                )
                m21StartRest.style.hideObjectOnPrint = True
                event = EventData(m21StartRest, -1, voiceIndex, self, offsetInScore=startTime)
                if event is not None:
                    self.events.append(event)
                startTime = opFrac(startTime + duration)

        for elementIndex, element in enumerate(m21Stream.recurse()
                                                    .getElementsNotOfClass(m21.stream.Stream)):
            event = EventData(element, elementIndex, voiceIndex, self)
            if event is not None:
                self.events.append(event)
                # Make a separate event for any DynamicWedge (in score's
                #   spannerBundle) that starts with this element.
                #   Why?
                #       1. So we don't put the end of the wedge in the same slice as the
                #           endNote (wedges end at the end time of the endNote, not at
                #           the start time of the endNote).
                #       2. So wedge starts/ends will go in their own slice if necessary (e.g.
                #           if we choose not to export the voice-with-only-invisible-rests we
                #           may have made to position them correctly.
                extraEvents: t.List[EventData] = self._parseDynamicWedgesStartedOrStoppedAt(event)
                if extraEvents:
                    self.events += extraEvents

        if emptyEndDuration > 0:
            # make m21 hidden rests totalling this duration, and pretend they
            # were at the end of m21Stream
            durations = Convert.getPowerOfTwoDurationsWithDotsAddingTo(emptyEndDuration)
            startTime = opFrac(self.startTime + self.duration - opFrac(emptyEndDuration))
            for duration in durations:
                m21EndRest: m21.note.Rest = m21.note.Rest(duration=m21.duration.Duration(duration))
                m21EndRest.style.hideObjectOnPrint = True
                event = EventData(m21EndRest, -1, voiceIndex, self, offsetInScore=startTime)
                if event is not None:
                    self.events.append(event)
                startTime = opFrac(startTime + duration)
Esempio n. 13
0
    def __init__(
        self,
        token: t.Optional[t.Union[HumdrumToken, str]] = None,
        duration: HumNumIn = opFrac(0)
    ) -> None:
        if isinstance(token, str):
            token = HumdrumToken(token)
        self._token: t.Optional[HumdrumToken] = token

        self._nextDur = opFrac(duration)
        #         self._prevDur = opFrac(0) # appears to be unused (never set to anything but zero)
        self._isTransfered: bool = False
Esempio n. 14
0
    def getValueHumNum(self, *ns1ns2key):  # -> HumNum:
        from converter21.humdrum import HumdrumToken
        value = self.getValue(*ns1ns2key)
        if value is None:
            return opFrac(0)

        if isinstance(value, HumdrumToken):
            return opFrac(0)

        # pylint: disable=bare-except
        try:
            return opFrac(value)  # can convert from int, float, Fraction, str
        except:
            return opFrac(0)
Esempio n. 15
0
 def isPowerOfTwoWithDots(quarterLength: HumNumIn) -> bool:
     ql: HumNum = opFrac(quarterLength)
     if Convert.isPowerOfTwo(ql):
         # power of two + no dots
         return True
     if Convert.isPowerOfTwo(ql * opFrac(Fraction(2, 3))):
         # power of two + 1 dot
         return True
     if Convert.isPowerOfTwo(ql * opFrac(Fraction(4, 7))):
         # power of two + 2 dots
         return True
     if Convert.isPowerOfTwo(ql * opFrac(Fraction(8, 15))):
         # power of two + 3 dots
         return True
     return False
Esempio n. 16
0
    def beat(self, beatDuration: t.Union[str, HumNumIn] = Fraction(1, 4)) -> HumNum:
        if isinstance(beatDuration, str):  # recip format string, e.g. '4' means 1/4
            beatDuration = Convert.recipToDuration(beatDuration)
        else:
            beatDuration = opFrac(beatDuration)

        if t.TYPE_CHECKING:
            assert isinstance(beatDuration, (float, Fraction))

        if beatDuration == 0:
            # avoid divide by 0, just return beatInMeasure = 0
            return opFrac(0)

        beatInMeasure = opFrac((self.durationFromBarline / beatDuration) + 1)
        return beatInMeasure
Esempio n. 17
0
    def addLabelAbbrToken(self, tok: str, timestamp: HumNumIn,
                          part: int, staff: int, voice: int,
                          maxPart: int) -> GridSlice:
        ts: HumNum = opFrac(timestamp)
        gs: GridSlice

        if not self.slices or self.slices[-1].timestamp < ts:
            # add a new GridSlice to an empty list or at end of list if timestamp
            # is after last entry in list.
            gs = GridSlice(self, ts, SliceType.LabelAbbrs, maxPart)
            gs.addToken(tok, part, staff, voice)
            self.slices.append(gs)
            return gs

        # search for existing line with same timestamp and the same slice type
        for gridSlice in self.slices:
            if gridSlice.timestamp == ts and gridSlice.isLabelAbbrSlice:
                gridSlice.addToken(tok, part, staff, voice)
                gs = gridSlice
                return gs

        # Couldn't find a place for the label abbr, so place at beginning of measure
        gs = GridSlice(self, ts, SliceType.LabelAbbrs, maxPart)
        gs.addToken(tok, part, staff, voice)
        self.slices.insert(0, gs)
        return gs
Esempio n. 18
0
    def __init__(
            self,
            measure: m21.stream.Measure,
            ownerStaff,      # StaffData
            measureIndex: int,
            prevMeasData: t.Optional['MeasureData']
    ) -> None:
        from converter21.humdrum import StaffData
        self.m21Measure: m21.stream.Measure = measure
        self.ownerStaff: StaffData = ownerStaff

        # inherited from ownerScore, ultimately
        self.spannerBundle: m21.spanner.SpannerBundle = ownerStaff.spannerBundle

        self._prevMeasData: t.Optional[MeasureData] = prevMeasData
        self._measureIndex: int = measureIndex
        self._startTime: HumNum = opFrac(-1)
        self._duration: HumNum = opFrac(-1)
        self._timeSigDur: HumNum = opFrac(-1)
        # leftBarlineStyle describes the left barline of this measure
        self.leftBarlineStyle: MeasureStyle = MeasureStyle.Regular
        # rightBarlineStyle describes the right barline of this measure
        self.rightBarlineStyle: MeasureStyle = MeasureStyle.Regular
        # measureStyle is a combination of this measure's leftBarlineStyle and
        # the previous measure's rightBarlineStyle.  It's the style we use when
        # writing a barline ('=') token.
        self.measureStyle: MeasureStyle = MeasureStyle.Regular

        self.leftBarlineFermataStyle: FermataStyle = FermataStyle.NoFermata
        self.rightBarlineFermataStyle: FermataStyle = FermataStyle.NoFermata
        # fermataStyle is a combination of this measure's leftBarlineFermataStyle and
        # the previous measure's rightBarlineFermataStyle.  It's the fermata style we
        # use when writing a barline ('=') token.
        self.fermataStyle: FermataStyle = FermataStyle.NoFermata

        self.inRepeatBracket: bool = False
        self.startsRepeatBracket: bool = False
        self.stopsRepeatBracket: bool = False
        self.repeatBracketName: str = ''

        self._measureNumberString: str = ''
        self.events: t.List[EventData] = []
        self.sortedEvents: t.List[SimultaneousEvents] = []  # list of startTime-binned events

        self._parseMeasure()  # generates _events and then sortedEvents (also barlines)
Esempio n. 19
0
    def recipToDuration(recip: str, scale: HumNumIn = opFrac(4)) -> HumNum:
        if recip in Convert._knownRecipDurationCache:
            return Convert._knownRecipDurationCache[recip]

        output: HumNum = opFrac(0)
        if 'q' in recip:
            # grace note, ignore printed rhythm
            Convert._knownRecipDurationCache[recip] = output
            return output  # 0

        subToken = recip.split(' ')[0]  # we're only interested in the first subtoken
        dotCount = subToken.count('.')

        m = re.search(r'([\d]+)%([\d]+)', subToken)
        if m is not None:
            # reciprocal rhythm 'denom%numer'
            output = opFrac(Fraction(int(m.group(2)), int(m.group(1))))
        else:
            m = re.search(r'([\d]+)', subToken)
            if m is None:
                # no rhythm found
                # don't fill cache with bad strings
                # Convert._knownRecipDurationCache[recip] = output
                return output  # 0

            if m.group(1).startswith('0'):
                # 0-symbol (e.g. '0' is 2/1, '00' is 4/1, '000' is 8/1, etc)
                zeroCount = m.group(1).count('0')
                output = opFrac(Fraction(pow(2, zeroCount), 1))
            else:
                # plain rhythm (denominator is in subToken, numerator is 1)
                output = opFrac(Fraction(1, int(m.group(1))))

        scale = opFrac(scale)
        dotFactor: HumNum = opFrac(1)
        if dotCount > 0:
            # if dotCount=1: dotFactor should be  3/2 (1.5, or one and a half)
            # if dotCount=2: dotFactor should be  7/4 (1.75, or one and three quarters)
            # if dotCount=3: dotFactor should be 15/8 (1.875, or one and seven eighths)
            # etc...
            #
            # dotFactor =   2^(dotCount+1) - 1
            #               ------------------
            #                   2^dotCount
            dotFactor = Fraction(pow(2, dotCount + 1) - 1, pow(2, dotCount))
            dotFactor = opFrac(dotFactor)

        output = opFrac(output * dotFactor * scale)
        Convert._knownRecipDurationCache[recip] = output
        return output
Esempio n. 20
0
def correlateHarmonies(currentMapping, music21Part):
    '''
    Adds a new :class:`~music21.stream.Part` to an existing offset mapping.
    
    >>> from music21 import corpus
    >>> from music21.figuredBass import checker
    >>> score = corpus.parse("corelli/opus3no1/1grave").measures(1,3)   
    >>> v0 = score[0]
    >>> offsetMapping = checker.createOffsetMapping(v0)    
    >>> v1 = score[1]
    >>> newMapping = checker.correlateHarmonies(offsetMapping, v1)
    >>> for (offsets, notes) in sorted(newMapping.items()):
    ...    print("{0!s:15}[{1!s:23}{2!s:21}]".format(offsets, notes[0], notes[1]))
    (0.0, 1.5)     [<music21.note.Note C>  <music21.note.Note A>]
    (1.5, 2.0)     [<music21.note.Note C>  <music21.note.Note A>]
    (2.0, 3.0)     [<music21.note.Note B-> <music21.note.Note G>]
    (3.0, 4.0)     [<music21.note.Note A>  <music21.note.Note F>]
    (4.0, 6.0)     [<music21.note.Note G>  <music21.note.Note E>]
    (6.0, 6.5)     [<music21.note.Note A>  <music21.note.Note F>]
    (6.5, 7.0)     [<music21.note.Note B-> <music21.note.Note F>]
    (7.0, 7.5)     [<music21.note.Note C>  <music21.note.Note F>]
    (7.5, 8.0)     [<music21.note.Note C>  <music21.note.Note E>]
    (8.0, 8.5)     [<music21.note.Note C>  <music21.note.Note D>]
    (8.5, 9.0)     [<music21.note.Note F>  <music21.note.Note D>]
    (9.0, 9.5)     [<music21.note.Note B-> <music21.note.Note D>]
    (9.5, 10.0)    [<music21.note.Note B-> <music21.note.Note G>]
    (10.0, 10.5)   [<music21.note.Note B-> <music21.note.Note E>]
    (10.5, 11.0)   [<music21.note.Note B-> <music21.note.Note C>]
    (11.0, 12.0)   [<music21.note.Note A>  <music21.note.Note F>]    
    '''
    newMapping = {}

    for offsets in sorted(currentMapping.keys()):
        (initOffset, endTime) = offsets
        notesInRange = music21Part.flat.iter.getElementsByClass(
            'GeneralNote').getElementsByOffset(
                initOffset,
                offsetEnd=endTime,
                includeEndBoundary=False,
                mustFinishInSpan=False,
                mustBeginInSpan=False,
                includeElementsThatEndAtStart=False)
        allNotesSoFar = currentMapping[offsets]
        for music21GeneralNote in notesInRange:
            newInitOffset = initOffset
            newEndTime = endTime
            if not music21GeneralNote.offset < initOffset:
                newInitOffset = music21GeneralNote.offset
            if not music21GeneralNote.offset + music21GeneralNote.quarterLength > endTime:
                newEndTime = opFrac(music21GeneralNote.offset +
                                    music21GeneralNote.quarterLength)
            allNotesCopy = copy.copy(allNotesSoFar)
            allNotesCopy.append(music21GeneralNote)
            newMapping[(newInitOffset, newEndTime)] = allNotesCopy

    return newMapping
Esempio n. 21
0
        def newNote(ts, n):
            '''
            Make a copy of the note and clear some settings
            '''
            nNew = copy.deepcopy(n)
            nNew.duration = dur
            if not copyPitches:
                nNew.pitch = n.pitch

            if nNew.stemDirection != 'noStem':
                nNew.stemDirection = None
            if not addTies:
                return nNew

            offsetDifference = common.opFrac(self.offset - ts.offset)
            endTimeDifference = common.opFrac(ts.endTime -
                                              (self.offset + quarterLength))
            if offsetDifference == 0 and endTimeDifference <= 0:
                addTie = None
            elif offsetDifference > 0:
                if endTimeDifference > 0:
                    addTie = 'continue'
                else:
                    addTie = 'stop'
            elif endTimeDifference > 0:
                addTie = 'start'
            else:
                raise VerticalityException('What possibility was missed?',
                                           offsetDifference, endTimeDifference,
                                           ts, self)

            if nNew.tie is not None and {nNew.tie.type, addTie
                                         } == startStopSet:
                nNew.tie.type = 'continue'
            elif nNew.tie is not None and nNew.tie.type == 'continue':
                nNew.tie.placement = None
            elif addTie is None and nNew.tie is not None:
                nNew.tie.placement = None

            elif addTie:
                nNew.tie = tie.Tie(addTie)

            return nNew
Esempio n. 22
0
 def _setOffset(self, offset):
     """
     sets the offset and if necessary, translates it to a Fraction for exact representation.
     """
     if offset is None:
         self._offset = None
     elif isinstance(offset, basestring):
         self._offset = offset
     else:
         self._offset = common.opFrac(offset)
Esempio n. 23
0
 def _setOffset(self, offset):
     '''
     sets the offset and if necessary, translates it to a Fraction for exact representation.
     '''
     if offset is None:
         self._offset = None
     elif isinstance(offset, basestring):
         self._offset = offset
     else:
         self._offset = common.opFrac(offset)
Esempio n. 24
0
    def testTuplets(self):

        from music21 import abcFormat
        from music21.abcFormat import testFiles

        tf = testFiles.testPrimitiveTuplet
        af = abcFormat.ABCFile()
        s = abcToStreamScore(af.readstr(tf))
        match = []
        # match strings for better comparison
        for n in s.flat.notesAndRests:
            match.append(n.quarterLength)
        shouldFind = [
            1.0 / 3,
            1.0 / 3,
            1.0 / 3,
            1.0 / 5,
            1.0 / 5,
            1.0 / 5,
            1.0 / 5,
            1.0 / 5,
            1.0 / 6,
            1.0 / 6,
            1.0 / 6,
            1.0 / 6,
            1.0 / 6,
            1.0 / 6,
            1.0 / 7,
            1.0 / 7,
            1.0 / 7,
            1.0 / 7,
            1.0 / 7,
            1.0 / 7,
            1.0 / 7,
            2.0 / 3,
            2.0 / 3,
            2.0 / 3,
            2.0 / 3,
            2.0 / 3,
            2.0 / 3,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            1.0 / 12,
            2.0,
        ]
        self.assertEqual(match, [common.opFrac(x) for x in shouldFind])
Esempio n. 25
0
def correlateHarmonies(currentMapping, music21Part):
    """
    Adds a new :class:`~music21.stream.Part` to an existing offset mapping.
    
    >>> from music21 import corpus
    >>> from music21.figuredBass import checker
    >>> score = corpus.parse("corelli/opus3no1/1grave").measures(1,3)   
    >>> v0 = score[0]
    >>> offsetMapping = checker.createOffsetMapping(v0)    
    >>> v1 = score[1]
    >>> newMapping = checker.correlateHarmonies(offsetMapping, v1)
    >>> for (offsets, notes) in sorted(newMapping.items()):
    ...    print("{0!s:15}[{1!s:23}{2!s:21}]".format(offsets, notes[0], notes[1]))
    (0.0, 1.5)     [<music21.note.Note C>  <music21.note.Note A>]
    (1.5, 2.0)     [<music21.note.Note C>  <music21.note.Note A>]
    (2.0, 3.0)     [<music21.note.Note B-> <music21.note.Note G>]
    (3.0, 4.0)     [<music21.note.Note A>  <music21.note.Note F>]
    (4.0, 6.0)     [<music21.note.Note G>  <music21.note.Note E>]
    (6.0, 6.5)     [<music21.note.Note A>  <music21.note.Note F>]
    (6.5, 7.0)     [<music21.note.Note B-> <music21.note.Note F>]
    (7.0, 7.5)     [<music21.note.Note C>  <music21.note.Note F>]
    (7.5, 8.0)     [<music21.note.Note C>  <music21.note.Note E>]
    (8.0, 8.5)     [<music21.note.Note C>  <music21.note.Note D>]
    (8.5, 9.0)     [<music21.note.Note F>  <music21.note.Note D>]
    (9.0, 9.5)     [<music21.note.Note B-> <music21.note.Note D>]
    (9.5, 10.0)    [<music21.note.Note B-> <music21.note.Note G>]
    (10.0, 10.5)   [<music21.note.Note B-> <music21.note.Note E>]
    (10.5, 11.0)   [<music21.note.Note B-> <music21.note.Note C>]
    (11.0, 12.0)   [<music21.note.Note A>  <music21.note.Note F>]    
    """
    newMapping = {}

    for offsets in sorted(currentMapping.keys()):
        (initOffset, endTime) = offsets
        notesInRange = music21Part.flat.getElementsByClass("GeneralNote").getElementsByOffset(
            initOffset,
            offsetEnd=endTime,
            includeEndBoundary=False,
            mustFinishInSpan=False,
            mustBeginInSpan=False,
            includeElementsThatEndAtStart=False,
        )
        allNotesSoFar = currentMapping[offsets]
        for music21GeneralNote in notesInRange:
            newInitOffset = initOffset
            newEndTime = endTime
            if not music21GeneralNote.offset < initOffset:
                newInitOffset = music21GeneralNote.offset
            if not music21GeneralNote.offset + music21GeneralNote.quarterLength > endTime:
                newEndTime = opFrac(music21GeneralNote.offset + music21GeneralNote.quarterLength)
            allNotesCopy = copy.copy(allNotesSoFar)
            allNotesCopy.append(music21GeneralNote)
            newMapping[(newInitOffset, newEndTime)] = allNotesCopy

    return newMapping
Esempio n. 26
0
    def barlineDuration(self) -> HumNum:
        # If necessary (and possible), analyze rhythm structure of the whole file,
        # so we can answer the question
        if not self._rhythmAnalyzed:
            if self._ownerFile:
                self._ownerFile.analyzeRhythmStructure()

        if self.isBarline:
            return self.durationToBarline

        return opFrac(self.durationFromBarline + self.durationToBarline)
Esempio n. 27
0
    def _parseEvent(self, element: m21.base.Music21Object,
                    offsetInScore: t.Optional[HumNumIn],
                    duration: t.Optional[HumNumIn]) -> None:
        if offsetInScore is not None:
            self._startTime = opFrac(offsetInScore)
        else:
            ownerScore = self.ownerMeasure.ownerStaff.ownerPart.ownerScore
            self._startTime = opFrac(
                element.getOffsetInHierarchy(ownerScore.m21Score))

        if duration is not None:
            self._duration = opFrac(duration)
        else:
            self._duration = opFrac(element.duration.quarterLength)

        # element.classes is a tuple containing the names (strings, not objects) of classes
        # that this object belongs to -- starting with the object's class name and going up
        # the mro() for the object.
        # So element.classes[0] is the name of the element's class.
        # e.g. 'Note' for m21.note.Note
        self._name = element.classes[0]
Esempio n. 28
0
    def assignDurationsToTrack(self, startToken: HumdrumToken,
                               startDur: HumNumIn) -> bool:
        sDur: HumNum = opFrac(startDur)
        if not startToken.hasRhythm:
            return self.isValid

        success: bool = self.prepareDurations(startToken,
                                              startToken.rhythmAnalysisState,
                                              sDur)
        if not success:
            return self.isValid
        return self.isValid
Esempio n. 29
0
    def getPowerOfTwoDurationsWithDotsAddingTo(quarterLength: HumNumIn) -> t.List[HumNum]:
        output: t.List[HumNum] = []
        ql: HumNum = opFrac(quarterLength)

        if Convert.isPowerOfTwoWithDots(ql):
            # power of two + maybe some dots
            output.append(ql)
            return output

        powerOfTwoQLAttempt: HumNum = opFrac(4)  # start with whole note
        smallest: HumNum = opFrac(Fraction(1, 2048))
        while powerOfTwoQLAttempt >= smallest:
            if ql >= powerOfTwoQLAttempt:
                output.append(powerOfTwoQLAttempt)
                ql = opFrac(ql - powerOfTwoQLAttempt)
            else:
                powerOfTwoQLAttempt = opFrac(powerOfTwoQLAttempt / 2)

            if Convert.isPowerOfTwoWithDots(ql):
                # power of two + maybe some dots
                output.append(ql)
                return output

        # we couldn't compute a full list so just return the original param
        return [opFrac(quarterLength)]
Esempio n. 30
0
    def analyzeRScale(self) -> bool:
        numActiveTracks: int = 0  # number of tracks currently having an active rscale parameter
        rscales: t.List[HumNum] = [opFrac(1)] * (self.maxTrack + 1)
        ttrack: int

        for line in self._lines:
            if line.isInterpretation:
                for token in line.tokens():
                    if not token.isKern:
                        continue

                    if not token.text.startswith('*rscale:'):
                        continue

                    value: HumNum = opFrac(1)
                    m = re.search(r'\*rscale:(\d+)/(\d+)', token.text)
                    if m is not None:
                        top: int = int(m.group(1))
                        bot: int = int(m.group(2))
                        value = opFrac(Fraction(top, bot))
                    else:
                        m = re.search(r'\*rscale:(\d+)', token.text)
                        if m is not None:
                            top = int(m.group(1))
                            value = opFrac(top)

                    ttrack = token.track
                    if value == 1:
                        if rscales[ttrack] != 1:
                            rscales[ttrack] = opFrac(1)
                            numActiveTracks -= 1
                    else:
                        if rscales[ttrack] == 1:
                            numActiveTracks += 1
                        rscales[ttrack] = value
                continue

            if numActiveTracks == 0:
                continue

            if not line.isData:
                continue

            for token in line.tokens():
                ttrack = token.track
                if rscales[ttrack] == 1:
                    continue
                if not token.isKern:
                    continue
                if token.isNull:
                    continue
                if token.duration < 0:
                    continue

                dur: HumNum = opFrac(token.durationNoDots * rscales[ttrack])
                vis: str = Convert.durationToRecip(dur)
                vis += '.' * token.dotCount
                token.setValue('LO', 'N', 'vis', vis)

        return True
Esempio n. 31
0
    def analyzeMeter(self) -> bool:
        self._barlines = []

        durationSum: HumNum = opFrac(0)
        foundFirstBarline: bool = False

        for line in self._lines:
            line.durationFromBarline = durationSum
            durationSum = opFrac(durationSum + line.duration)
            if line.isBarline:
                foundFirstBarline = True
                self._barlines.append(line)
                durationSum = opFrac(0)
            elif line.isData and not foundFirstBarline:
                # pickup measure, so set the first barline to the start of the file
                self._barlines.append(self._lines[0])
                foundFirstBarline = True

        durationSum = opFrac(0)
        for line in reversed(self._lines):
            durationSum = opFrac(durationSum + line.duration)
            line.durationToBarline = durationSum
            if line.isBarline:
                durationSum = opFrac(0)

        return True
Esempio n. 32
0
    def __init__(self, ownerGrid) -> None:
        from converter21.humdrum import HumGrid
        if not isinstance(ownerGrid, HumGrid):
            raise HumdrumInternalError('invalid ownerGrid')
        self._ownerGrid: HumGrid = ownerGrid
        self.slices: t.List[GridSlice] = []
        self._timestamp: HumNum = opFrac(-1)
        self._duration: HumNum = opFrac(-1)
        self._timeSigDur: HumNum = opFrac(-1)
        self.leftBarlineStyle: MeasureStyle = MeasureStyle.Regular
        self.rightBarlineStyle: MeasureStyle = MeasureStyle.Regular
        self.fermataStylePerStaff: t.List[FermataStyle] = []
        self.measureStyle: MeasureStyle = MeasureStyle.Regular
        self.measureNumberString: str = ''

        self.inRepeatBracket: bool = False
        self.startsRepeatBracket: bool = False
        self.stopsRepeatBracket: bool = False
        self.repeatBracketName: str = ''

        # only used on last measure in score
        self.rightBarlineFermataStylePerStaff: t.List[FermataStyle] = []
Esempio n. 33
0
        def newNote(ts, n):
            '''
            Make a copy of the note and clear some settings
            '''
            nNew = copy.deepcopy(n)
            nNew.duration = dur
            if nNew.stemDirection != 'noStem':
                nNew.stemDirection = None
            if not addTies:
                return nNew            
            
            offsetDifference = common.opFrac(self.offset - ts.offset)
            endTimeDifference = common.opFrac(ts.endTime - (self.offset + quarterLength))
            if offsetDifference == 0 and endTimeDifference <= 0:
                addTie = None
            elif offsetDifference > 0:
                if endTimeDifference > 0:
                    addTie = 'continue'
                else:
                    addTie = 'stop'
            elif endTimeDifference > 0:
                addTie = 'start'
            else:
                raise VerticalityException("What possibility was missed?", 
                                offsetDifference, endTimeDifference, ts, self)            
            
            
            if nNew.tie is not None and {nNew.tie.type, addTie} == startStopSet:
                nNew.tie.type = 'continue'  
            elif nNew.tie is not None and nNew.tie.type == 'continue':
                nNew.tie.placement = None
            elif addTie is None and nNew.tie is not None:
                nNew.tie.placement = None
            
            elif addTie:
                nNew.tie = tie.Tie(addTie)

            return nNew
Esempio n. 34
0
    def recurseGetTreeByClass(inputStream,
                              currentParentage,
                              initialOffset,
                              outputTree=None):
        lastParentage = currentParentage[-1]

        if outputTree is None:
            outputTree = treeClass(source=lastParentage)

        # do this to avoid munging activeSites
        inputStreamElements = inputStream._elements[:] + inputStream._endElements
        parentEndTime = initialOffset + lastParentage.duration.quarterLength

        for element in inputStreamElements:
            flatOffset = common.opFrac(
                lastParentage.elementOffset(element) + initialOffset)

            if element.isStream and flatten is not False:  # True or "semiFlat"
                localParentage = currentParentage + (element, )
                recurseGetTreeByClass(
                    element,  # put the elements into the current tree...
                    currentParentage=localParentage,
                    initialOffset=flatOffset,
                    outputTree=outputTree)
                if flatten != 'semiFlat':
                    continue  # do not insert the stream itself unless we are doing semiflat

            if classList and not element.isClassOrSubclass(classList):
                continue

            endTime = flatOffset + element.duration.quarterLength

            if useTimespans:
                pitchedTimespan = spans.PitchedTimespan(
                    element=element,
                    parentage=tuple(reversed(currentParentage)),
                    parentOffset=initialOffset,
                    parentEndTime=parentEndTime,
                    offset=flatOffset,
                    endTime=endTime)
                outputTree.insert(pitchedTimespan)
            elif groupOffsets is False:
                # for sortTuples
                position = element.sortTuple(lastParentage)
                flatPosition = position.modify(offset=flatOffset)
                outputTree.insert(flatPosition, element)
            else:
                outputTree.insert(flatOffset, element)

        return outputTree
Esempio n. 35
0
    def timeToNextEvent(self) -> t.Optional[OffsetQL]:
        '''
        Returns a float or Fraction of the quarterLength to the next
        event (usually the next Verticality, but also to the end of the piece).

        Returns None if there is no next event, such as when the verticality
        is divorced from its tree.
        '''
        nextOffset = self.nextStartOffset
        if nextOffset is None:
            if self.timespanTree is None:
                return None
            nextOffset = self.timespanTree.endTime
        return common.opFrac(nextOffset - self.offset)
Esempio n. 36
0
    def recurseGetTreeByClass(inputStream,
                       currentParentage,
                       initialOffset,
                       outputTree=None):
        lastParentage = currentParentage[-1]

        if outputTree is None:
            outputTree = treeClass(source=lastParentage)

        # do this to avoid munging activeSites
        inputStreamElements = inputStream._elements[:] + inputStream._endElements
        parentEndTime = initialOffset + lastParentage.duration.quarterLength


        for element in inputStreamElements:
            flatOffset = common.opFrac(lastParentage.elementOffset(element) + initialOffset)

            if element.isStream and flatten is not False: # True or "semiFlat"
                localParentage = currentParentage + (element,)
                recurseGetTreeByClass(element, # put the elements into the current tree...
                                      currentParentage=localParentage,
                                      initialOffset=flatOffset,
                                      outputTree=outputTree)
                if flatten != 'semiFlat':
                    continue  # do not insert the stream itself unless we are doing semiflat

            if classList and not element.isClassOrSubclass(classList):
                continue

            endTime = flatOffset + element.duration.quarterLength

            if useTimespans:
                pitchedTimespan = spans.PitchedTimespan(element=element,
                                                    parentage=tuple(reversed(currentParentage)),
                                                    parentOffset=initialOffset,
                                                    parentEndTime=parentEndTime,
                                                    offset=flatOffset,
                                                    endTime=endTime)
                outputTree.insert(pitchedTimespan)
            elif groupOffsets is False:
                # for sortTuples
                position = element.sortTuple(lastParentage)
                flatPosition = position.modify(offset=flatOffset)
                outputTree.insert(flatPosition, element)
            else:
                outputTree.insert(flatOffset, element)

        return outputTree
Esempio n. 37
0
    def getSiteByOffset(self, offset):
        """
        For a given offset return the site that fits it

        More than one Site may have the same offset; this at one point returned
        the last site added by sorting time, but now we use a dict, so there's
        no guarantee that the one you want will be there -- need orderedDicts!

        ::

            >>> import fractions
            >>> class Mock(base.Music21Object):
            ...     pass
            ...
            >>> aSite = Mock()
            >>> bSite = Mock()
            >>> cSite = Mock()
            >>> sitesObj = sites.Sites()
            >>> sitesObj.add(aSite, 2)
            >>> sitesObj.add(bSite, 10.0/3)
            >>> aSite is sitesObj.getSiteByOffset(2)
            True
            >>> bSite is sitesObj.getSiteByOffset(fractions.Fraction(10, 3))
            True
            >>> bSite is sitesObj.getSiteByOffset(3.33333333333)
            True

        """
        match = None
        offset = common.opFrac(offset)
        for siteId in self.siteDict:
            # might need to use almost equals here
            matched = False
            if self.siteDict[siteId].offsetRational == offset:
                matched = True
            if matched is True:
                if self.siteDict[siteId].isDead:
                    return None
                match = self.siteDict[siteId].site
                break
        return match
Esempio n. 38
0
    def expand(self, ts=None, ks=None):
        '''
        The meat of it all -- expand one rule completely and return a list of Measure objects.
        '''
        if ts is None:
            ts = meter.TimeSignature('4/4')
        if ks is None:
            ks = key.Key('C')
        measures = []

        lastRegularAtom = None
        lastChord = None
        
        for content, sep, numReps in self._measureGroups():
            lastChordIsInSameMeasure = False
            if sep == "$":
                if content not in self.parent.rules:
                    raise CTRuleException("Cannot expand rule {0} in {2}".format(content, self))
                rule = self.parent.rules[content]
                for i in range(numReps):
                    returnedMeasures = rule.expand(ts, ks)
                    self.insertKsTs(returnedMeasures[0], ts, ks)
                    for m in returnedMeasures:
                        tsEs = m.getElementsByClass('TimeSignature', returnStreamSubClass='list')
                        for returnedTs in tsEs:
                            if returnedTs is not ts:
                                ts = copy.deepcopy(ts) # the TS changed mid-rule; create a new one for return.
                    
                    measures.extend(returnedMeasures)
            elif sep == "|":
                m = stream.Measure()
                atoms = content.split()
                # key/timeSig pass...
                regularAtoms = []
                for atom in atoms:
                    if atom.startswith('['):
                        atomContent = atom[1:-1]
                        if atomContent == '0':
                            ts = meter.TimeSignature('4/4') # irregular meter.  Cannot fully represent; 
                            #TODO: replace w/ senza misura when possible. 
                                                        
                        elif '/' in atomContent: # only one key / ts per measure.
                            ts = meter.TimeSignature(atomContent)
                        else:
                            ks = key.Key(key.convertKeyStringToMusic21KeyString(atomContent))
                            
                    elif atom == '.':
                        if lastRegularAtom is None:
                            raise CTRuleException(" . w/o previous atom: %s" % self)
                        regularAtoms.append(lastRegularAtom)
                    elif atom in ("", None):
                        pass
                    else:
                        regularAtoms.append(atom)
                        lastRegularAtom = atom
                numAtoms = len(regularAtoms)
                if numAtoms == 0:
                    continue # maybe just ts and ks setting

                self.insertKsTs(m, ts, ks)
                
                atomLength = common.opFrac(ts.barDuration.quarterLength / numAtoms)            
                for atom in regularAtoms:
                    if atom == 'R':
                        rest = note.Rest(quarterLength=atomLength)
                        lastChord = None
                        lastChordIsInSameMeasure = False
                        m.append(rest)
                    else:
                        atom = self.fixupChordAtom(atom)
                        rn = roman.RomanNumeral(atom, ks)
                        if self.isSame(rn, lastChord) and lastChordIsInSameMeasure:
                            lastChord.duration.quarterLength += atomLength
                            m.elementsChanged()
                        else:
                            rn.duration.quarterLength = atomLength
                            self.addOptionalTieAndLyrics(rn, lastChord)
                            lastChord = rn
                            lastChordIsInSameMeasure = True
                            m.append(rn)
                measures.append(m)
                for i in range(1, numReps):
                    measures.append(copy.deepcopy(m))
            else:    
                environLocal.warn("Rule found without | or $, ignoring: '{0}','{1}': in {2}".format(
                                                                        content, sep, self.text))
                #pass
        if len(measures) > 0:
            for m in measures:
                noteIter = m.recurse().notes
                if noteIter and (self.parent is None or self.parent.labelSubsectionsOnScore is True) and self.LHS != 'S':
                    rn = noteIter[0]
                    lyricNum = len(rn.lyrics) + 1
                    rn.lyrics.append(note.Lyric(self.LHS, number=lyricNum))       
                    break                 
                
        return measures
Esempio n. 39
0
def reBar(music21Part, inPlace=True):
    """
    Re-bar overflow measures using the last known time signature.

    >>> from music21 import corpus
    >>> irl2 = corpus.parse("irl", number=2)
    >>> irl2.metadata.title
    'Aililiu na Gamhna, S.35'
    >>> music21Part = irl2[1]


    The whole part is in 2/4 time, but there are some measures expressed in 4/4 time
    without an explicit time signature change, an error in abc parsing due to the
    omission of barlines. The method will split those measures such that they conform
    to the last time signature, in this case 2/4. The default is to reBar in place.
    The measure numbers are updated accordingly. 
    
    (NOTE: reBar is called automatically in abcToStreamPart, hence not demonstrated below...)

    The key signature and clef are assumed to be the same in the second measure after the
    split, so both are omitted. If the time signature is not the same in the second measure,
    the new time signature is indicated, and the measure following returns to the last time
    signature, except in the case that a new time signature is indicated.

    >>> music21Part.measure(15).show("text")
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note A>
    >>> music21Part.measure(16).show("text")
    {0.0} <music21.note.Note A>
    {0.5} <music21.note.Note B->
    {1.0} <music21.note.Note A>
    {1.5} <music21.note.Note G>

    An example where the time signature wouldn't be the same. This score is
    mistakenly marked as 4/4, but has some measures that are longer.

    >>> irl15 = corpus.parse("irl", number=15)
    >>> irl15.metadata.title
    'Esternowe, S. 60'
    >>> music21Part2 = irl15.parts[0] # 4/4 time signature
    >>> music21Part2.measure(1).show("text")
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note A>
    {1.5} <music21.note.Note G>
    {2.0} <music21.note.Note E>
    {2.5} <music21.note.Note G>
    >>> music21Part2.measure(1)[-1].duration.quarterLength
    1.5

    >>> music21Part2.measure(2).show("text")
    {0.0} <music21.meter.TimeSignature 1/8>
    {0.0} <music21.note.Note E>
    """
    if not inPlace:
        music21Part = copy.deepcopy(music21Part)
    lastTimeSignature = None
    measureNumberOffset = 0 # amount to shift current measure numbers
    allMeasures = music21Part.getElementsByClass(stream.Measure)
    for measureIndex in range(len(allMeasures)):
        music21Measure = allMeasures[measureIndex]
        if music21Measure.timeSignature is not None:
            lastTimeSignature = music21Measure.timeSignature

        if lastTimeSignature is None:
            raise ABCTranslateException("No time signature found in this Part")

        tsEnd = lastTimeSignature.barDuration.quarterLength
        mEnd = common.opFrac(music21Measure.highestTime)
        music21Measure.number += measureNumberOffset
        if mEnd > tsEnd:
            m1, m2 = music21Measure.splitAtQuarterLength(tsEnd)
            m2.timeSignature = None
            if lastTimeSignature.barDuration.quarterLength != m2.highestTime:
                try:
                    m2.timeSignature = m2.bestTimeSignature()
                except exceptions21.StreamException as e:
                    raise ABCTranslateException("Problem with measure %d (%r): %s" % (music21Measure.number, music21Measure, e))
                if measureIndex != len(allMeasures) - 1:
                    if allMeasures[measureIndex+1].timeSignature is None:
                        allMeasures[measureIndex+1].timeSignature = lastTimeSignature
            m2.keySignature = None # suppress the key signature
            m2.clef = None # suppress the clef
            m2.number = m1.number + 1
            measureNumberOffset += 1
            music21Part.insert(common.opFrac(m1.offsetRational + m1.highestTime), m2)
        
        #elif (mEnd + music21Measure.paddingLeft) < tsEnd and measureIndex != len(allMeasures) - 1:
        #    The first and last measures are allowed to be incomplete
        #    music21Measure.timeSignature = music21Measure.bestTimeSignature()
        #    if allMeasures[measureIndex+1].timeSignature is None:
        #        allMeasures[measureIndex+1].timeSignature = lastTimeSignature
        #

    if not inPlace:
        return music21Part
Esempio n. 40
0
def makeBeams(s, inPlace=False):
    '''
    Return a new Measure, or Stream of Measures, with beams applied to all
    notes. Measures with Voices will process voices independently.

    Note that `makeBeams()` is automatically called in show('musicxml') and
    other formats if there is no beaming information in the piece (see
    `haveBeamsBeenMade`).

    If `inPlace` is True, this is done in-place; if `inPlace` is False,
    this returns a modified deep copy.

    .. note: Before Version 1.6, `inPlace` default was `True`; now `False`
             like most `inPlace` options in music21.  Also, in 1.8, no tuplets are made
             automatically.  Use makeTupletBrackets()

    See :meth:`~music21.meter.TimeSignature.getBeams` for the algorithm used.

    >>> from music21 import meter
    >>> from music21 import stream

    >>> aMeasure = stream.Measure()
    >>> aMeasure.timeSignature = meter.TimeSignature('4/4')
    >>> aNote = note.Note()
    >>> aNote.quarterLength = .25
    >>> aMeasure.repeatAppend(aNote,16)
    >>> bMeasure = aMeasure.makeBeams(inPlace=False)

    >>> for i in range(0, 4):
    ...   print("%d %r" % (i, bMeasure.notes[i].beams))
    0 <music21.beam.Beams <music21.beam.Beam 1/start>/<music21.beam.Beam 2/start>>
    1 <music21.beam.Beams <music21.beam.Beam 1/continue>/<music21.beam.Beam 2/stop>>
    2 <music21.beam.Beams <music21.beam.Beam 1/continue>/<music21.beam.Beam 2/start>>
    3 <music21.beam.Beams <music21.beam.Beam 1/stop>/<music21.beam.Beam 2/stop>>

    OMIT_FROM_DOCS
    TODO: inPlace=False does not work in many cases
    '''
    from music21 import stream

    #environLocal.printDebug(['calling Stream.makeBeams()'])
    if not inPlace:  # make a copy
        returnObj = copy.deepcopy(s)
    else:
        returnObj = s

    #if s.isClass(Measure):
    if 'Measure' in s.classes:
    #if s.isClassOrSubclass('Measure'):
        mColl = []  # store a list of measures for processing
        mColl.append(returnObj)
    elif s.iter.getElementsByClass('Measure'):
        mColl = list(returnObj.iter.getElementsByClass('Measure'))  # a list of measures
    else:
        raise stream.StreamException(
            'cannot process a stream that neither is a Measure nor has '
            'Measures')

    lastTimeSignature = None

    for m in mColl:
        # this means that the first of a stream of time signatures will
        # be used
        if m.timeSignature is not None:
            lastTimeSignature = m.timeSignature
        if lastTimeSignature is None:
            #environLocal.printDebug([
            #    'makeBeams(): lastTimeSignature is None: cannot process'])
            # TODO: Reduce to warning...
            raise stream.StreamException(
                'cannot process beams in a Measure without a time signature')
        noteGroups = []
        if m.hasVoices():
            for v in m.voices:
                noteGroups.append(v.iter.notesAndRests.stream())
        else:
            noteGroups.append(m.iter.notesAndRests.stream())

        #environLocal.printDebug([
        #    'noteGroups', noteGroups, 'len(noteGroups[0])',
        #    len(noteGroups[0])])

        for noteStream in noteGroups:
            if len(noteStream) <= 1:
                continue  # nothing to beam
            durList = []
            for n in noteStream:
                durList.append(n.duration)
            #environLocal.printDebug([
            #    'beaming with ts', lastTimeSignature, 'measure', m, durList,
            #    noteStream[0], noteStream[1]])

            # error check; call before sending to time signature, as, if this
            # fails, it represents a problem that happens before time signature
            # processing
            durSum = opFrac(sum([d.quarterLength for d in durList]))
            barQL = lastTimeSignature.barDuration.quarterLength

            if durSum > barQL:
                #environLocal.printDebug([
                #    'attempting makeBeams with a bar that contains durations
                #    that sum greater than bar duration (%s > %s)' %
                #    (durSum, barQL)])
                continue
            # getBeams can take a list of Durations; however, this cannot
            # distinguish a Note from a Rest; thus, we can submit a flat
            # stream of note or note-like entities; will return
            # the same list of beam objects

            offset = 0.0
            if m.paddingLeft != 0.0:
                offset = opFrac(m.paddingLeft)
            elif (noteStream.highestTime <
                lastTimeSignature.barDuration.quarterLength):
                offset = (lastTimeSignature.barDuration.quarterLength -
                    noteStream.highestTime)
            beamsList = lastTimeSignature.getBeams(
                noteStream, measureStartOffset=offset)

            for i in range(len(noteStream)):
                # this may try to assign a beam to a Rest
                noteStream[i].beams = beamsList[i]

    del mColl  # remove Stream no longer needed
    if inPlace is not True:
        return returnObj
Esempio n. 41
0
def makeTupletBrackets(s, inPlace=False):
    '''
    Given a Stream of mixed durations, designates the first and last tuplet of any group
    of tuplets as the start or end of the tuplet, respectively.

    Changed in 1.8::
    
        * `inPlace` is False by default
        * to incorporate duration.updateTupletType, can take a list of durations
                    
    TODO: does not handle nested tuplets

    >>> n = note.Note()
    >>> n.duration.quarterLength = 1.0/3
    >>> s = stream.Stream()
    >>> s.insert(0, meter.TimeSignature('2/4'))
    >>> s.repeatAppend(n, 6)
    >>> tupletTypes = [x.duration.tuplets[0].type for x in s.notes]
    >>> tupletTypes
    [None, None, None, None, None, None]
    >>> stream.makeNotation.makeTupletBrackets(s, inPlace=True)
    >>> tupletTypes = [x.duration.tuplets[0].type for x in s.notes]
    >>> tupletTypes
    ['start', None, 'stop', 'start', None, 'stop']
    '''
    durationList = []
    
    # legacy -- works on lists not just streams...
    if isinstance(s, list) or isinstance(s, tuple):
        durationList = s
    else:
        # Stream, as it should be...
        if not inPlace:  # make a copy
            returnObj = copy.deepcopy(s)
        else:
            returnObj = s
    
        # only want to look at notes
        notes = returnObj.notesAndRests
        for n in notes:
            durationList.append(n.duration)

    tupletMap = [] # a list of (tuplet obj / Duration) pairs
    for dur in durationList: # all Duration objects
        tupletList = dur.tuplets
        if tupletList in [(), None]: # no tuplets, length is zero
            tupletMap.append([None, dur])
        elif len(tupletList) > 1:
            #for i in range(len(tuplets)):
            #    tupletMap.append([tuplets[i],dur])
            environLocal.warn('got multi-tuplet duration; cannot yet handle this. %s' % repr(tupletList))
        elif len(tupletList) == 1:
            tupletMap.append([tupletList[0], dur])
            if tupletList[0] != dur.tuplets[0]:
                raise Exception('cannot access Tuplets object from within DurationTuple.')
        else:
            raise Exception('cannot handle these tuplets: %s' % tupletList)


    # have a list of tuplet, Duration pairs
    completionCount = 0 # qLen currently filled
    completionTarget = None # qLen necessary to fill tuplet
    for i in range(len(tupletMap)):
        tupletObj, dur = tupletMap[i]

        if i > 0:
            tupletPrevious = tupletMap[i - 1][0]
        else:
            tupletPrevious = None

        if i < len(tupletMap) - 1:
            tupletNext = tupletMap[i + 1][0]
#            if tupletNext != None:
#                nextNormalType = tupletNext.durationNormal.type
#            else:
#                nextNormalType = None
        else:
            tupletNext = None
#            nextNormalType = None

#         environLocal.printDebug(['updateTupletType previous, this, next:',
#                                  tupletPrevious, tuplet, tupletNext])

        if tupletObj is not None:
#            thisNormalType = tuplet.durationNormal.type
            completionCount = opFrac(completionCount + dur.quarterLength)
            # if previous tuplet is None, always start
            # always reset completion target
            if tupletPrevious is None or completionTarget is None:
                if tupletNext is None: # single tuplet w/o tuplets either side
                    tupletObj.type = 'startStop'
                    tupletObj.bracket = False
                    completionCount = 0 # reset
                else:
                    tupletObj.type = 'start'
                    # get total quarter length of this tuplet
                    completionTarget = tupletObj.totalTupletLength()
                    #environLocal.printDebug(['starting tuplet type, value:',
                    #                         tuplet, tuplet.type])
                    #environLocal.printDebug(['completion count, target:',
                    #                         completionCount, completionTarget])

            # if tuplet next is None, always stop
            # if both previous and next are None, just keep a start

            # this, below, is optional:
            # if next normal type is not the same as this one, also stop
            elif (tupletNext is None or completionCount >= completionTarget):
                tupletObj.type = 'stop' # should be impossible once frozen...
                completionTarget = None # reset
                completionCount = 0 # reset
                #environLocal.printDebug(['stopping tuplet type, value:',
                #                         tuplet, tuplet.type])
                #environLocal.printDebug(['completion count, target:',
                #                         completionCount, completionTarget])

            # if tuplet next and previous not None, increment
            elif tupletPrevious != None and tupletNext != None:
                # do not need to change tuplet type; should be None
                pass
                #environLocal.printDebug(['completion count, target:',
                #                         completionCount, completionTarget])

    if not inPlace:
        return returnObj
Esempio n. 42
0
    def makeElement(self, 
                    quarterLength=1.0, 
                    *,
                    addTies=True,
                    addPartIdAsGroup=False,
                    removeRedundantPitches=True,
                    gatherArticulations='single',
                    gatherExpressions='single'
                    ):
        r'''
        Makes a Chord or Rest from this verticality and quarterLength.

        >>> score = tree.makeExampleScore()
        >>> scoreTree = tree.fromStream.asTimespans(score, flatten=True,
        ...            classList=(note.Note, chord.Chord))
        >>> verticality = scoreTree.getVerticalityAt(4.0)
        >>> verticality
        <Verticality 4.0 {E#3 G3}>
        >>> verticality.startTimespans
        (<PitchedTimespan (4.0 to 5.0) <music21.note.Note G>>, 
         <PitchedTimespan (4.0 to 6.0) <music21.note.Note E#>>)
         
        >>> el = verticality.makeElement(2.0)
        >>> el
        <music21.chord.Chord E#3 G3>
        >>> el.duration.quarterLength
        2.0
        >>> el.duration.type
        'half'

        If there is nothing there, then a Rest is created

        >>> verticality = scoreTree.getVerticalityAt(400.0)
        >>> verticality
        <Verticality 400.0 {}>
        >>> el = verticality.makeElement(1./3)
        >>> el
        <music21.note.Rest rest>
        >>> el.duration.fullName
        'Eighth Triplet (1/3 QL)'


        >>> n1 = note.Note('C4')
        >>> n2 = note.Note('C4')
        >>> s = stream.Score()
        >>> s.insert(0, n1)
        >>> s.insert(0.5, n2)
        >>> scoreTree = s.asTimespans()
        >>> verticality = scoreTree.getVerticalityAt(0.5)
        >>> c = verticality.makeElement(0.5)
        >>> c
        <music21.chord.Chord C4>
        
        >>> c = verticality.makeElement(0.5, removeRedundantPitches=False)
        >>> c
        <music21.chord.Chord C4 C4>
        
        gatherArticulations and gatherExpressions can be True, False, or (default) 'single'.
        
        * If False, no articulations (or expressions) are transferred to the chord.
        * If True, all articulations are transferred to the chord.
        * If 'single', then no more than one articulation of each class (chosen from the lowest
          note) will be added.  This way, the chord does not get 4 fermatas, etc.
                   
        >>> n1 = note.Note('C4')
        >>> n2 = note.Note('D4')
        >>> s = stream.Stream()
        >>> s.insert(0, n1)
        >>> s.insert(0.5, n2)

        >>> class AllAttachArticulation(articulations.Articulation):
        ...     def __init__(self):
        ...         super().__init__()
        ...         self.tieAttach = 'all'

        >>> class OtherAllAttachArticulation(articulations.Articulation):
        ...     def __init__(self):
        ...         super().__init__()
        ...         self.tieAttach = 'all'

        
        >>> n1.articulations.append(articulations.Accent())
        >>> n1.articulations.append(AllAttachArticulation())
        >>> n1.expressions.append(expressions.Fermata())

        >>> n2.articulations.append(articulations.Staccato())
        >>> n2.articulations.append(AllAttachArticulation())
        >>> n2.articulations.append(OtherAllAttachArticulation())
        >>> n2.expressions.append(expressions.Fermata())

        >>> scoreTree = s.asTimespans()
        
        >>> verticality = scoreTree.getVerticalityAt(0.0)
        >>> c = verticality.makeElement(1.0)
        >>> c.expressions
        [<music21.expressions.Fermata>]
        >>> c.articulations
        [<music21.articulations.Accent>, <music21.articulations.AllAttachArticulation>]

        >>> verticality = scoreTree.getVerticalityAt(0.5)


        Here there will be no expressions, because there is no note ending
        at 0.75 and Fermatas attach to the last note:
        
        >>> c = verticality.makeElement(0.25)
        >>> c.expressions
        []

        >>> c = verticality.makeElement(0.5)        
        >>> c.expressions
        [<music21.expressions.Fermata>]
        
        Only two articulations, since accent attaches to beginning and staccato attaches to last
        and we are beginning after the start of the first note (with an accent)
        and cutting right through the second note (with a staccato)
        
        >>> c.articulations
        [<music21.articulations.AllAttachArticulation>, 
         <music21.articulations.OtherAllAttachArticulation>]
        
        >>> c = verticality.makeElement(0.5, gatherArticulations=True)
        >>> c.articulations
        [<music21.articulations.AllAttachArticulation>, 
         <music21.articulations.AllAttachArticulation>,
         <music21.articulations.OtherAllAttachArticulation>]

        >>> c = verticality.makeElement(0.5, gatherArticulations=False)
        >>> c.articulations
        []

        >>> verticality = scoreTree.getVerticalityAt(1.0)
        >>> c = verticality.makeElement(0.5)
        >>> c.expressions
        [<music21.expressions.Fermata>]
        >>> c.articulations
        [<music21.articulations.Staccato>,
         <music21.articulations.AllAttachArticulation>,
         <music21.articulations.OtherAllAttachArticulation>]

        '''
        if not self.pitchSet:
            r = note.Rest()
            r.duration.quarterLength = common.opFrac(quarterLength)
            return r
        
        # easy stuff done, time to get to the hard stuff...

        c = chord.Chord()
        c.duration.quarterLength = common.opFrac(quarterLength)
        dur = c.duration
        
        seenPitches = set()
        notesToAdd = {}
                
        startStopSet = {'start', 'stop'}
        pitchBust = 0 # used if removeRedundantPitches is False.


        def newNote(ts, n):
            '''
            Make a copy of the note and clear some settings
            '''
            nNew = copy.deepcopy(n)
            nNew.duration = dur
            if nNew.stemDirection != 'noStem':
                nNew.stemDirection = None
            if not addTies:
                return nNew            
            
            offsetDifference = common.opFrac(self.offset - ts.offset)
            endTimeDifference = common.opFrac(ts.endTime - (self.offset + quarterLength))
            if offsetDifference == 0 and endTimeDifference <= 0:
                addTie = None
            elif offsetDifference > 0:
                if endTimeDifference > 0:
                    addTie = 'continue'
                else:
                    addTie = 'stop'
            elif endTimeDifference > 0:
                addTie = 'start'
            else:
                raise VerticalityException("What possibility was missed?", 
                                offsetDifference, endTimeDifference, ts, self)            
            
            
            if nNew.tie is not None and {nNew.tie.type, addTie} == startStopSet:
                nNew.tie.type = 'continue'  
            elif nNew.tie is not None and nNew.tie.type == 'continue':
                nNew.tie.placement = None
            elif addTie is None and nNew.tie is not None:
                nNew.tie.placement = None
            
            elif addTie:
                nNew.tie = tie.Tie(addTie)

            return nNew
        
        def conditionalAdd(ts, n):
            '''
            Add an element only if it is not already in the chord.
            
            If it has more tie information than the previously
            added note, then remove the previously added note and add it
            '''
            nonlocal pitchBust # love Py3!!!
            p = n.pitch
            pitchKey = p.nameWithOctave

            pitchGroup = None
            if addPartIdAsGroup:
                partContext = n.getContextByClass('Part')
                if partContext is not None:
                    pidStr = str(partContext.id)
                    pitchGroup = pidStr.replace(' ', '_') # spaces are not allowed as group names
                    n.pitch.groups.append(pitchGroup)
                    n.groups.append(pitchGroup)
        
            
            if pitchKey not in seenPitches:
                seenPitches.add(pitchKey)                    
                notesToAdd[pitchKey] = newNote(ts, n)
                return
            elif not removeRedundantPitches:
                notesToAdd[pitchKey + str(pitchBust)] = newNote(ts, n)
                pitchBust += 1
                return
            elif addPartIdAsGroup:
                notesToAdd[pitchKey].groups.append(pitchGroup)
                notesToAdd[pitchKey].pitch.groups.append(pitchGroup)


            if not addTies:
                return

            # else add derivation once multiple derivations are allowed.
            oldNoteTie = notesToAdd[pitchKey].tie
            if oldNoteTie is not None and oldNoteTie.type == 'continue':
                return # previous note was as good or better
            
            possibleNewNote = newNote(ts, n)
            possibleNewNote.groups = notesToAdd[pitchKey].groups
            
            if possibleNewNote.tie is None:
                return # do nothing
            elif oldNoteTie is None:
                notesToAdd[pitchKey] = possibleNewNote # a better note to add
            elif {oldNoteTie.type, possibleNewNote.tie.type} == startStopSet:
                notesToAdd[pitchKey].tie.type = 'continue'
            elif possibleNewNote.tie.type == 'continue':
                notesToAdd[pitchKey] = possibleNewNote # a better note to add
            elif possibleNewNote.tie.type == oldNoteTie.type:
                return
            else:
                raise VerticalityException("Did I miss one? ", possibleNewNote.tie, oldNoteTie)
            
            
        for ts in self.startAndOverlapTimespans:
            if not isinstance(ts, spans.PitchedTimespan):
                continue
            el = ts.element
            if 'Chord' in el.classes:
                if len(el) == 0: # pylint: disable=len-as-condition
                    continue

                if el.articulations or el.expressions:
                    firstSubEl = copy.deepcopy(el[0]) # this makes an additional deepcopy
                    firstSubEl.articulations += el.articulations
                    firstSubEl.expressions += el.expressions
                else:
                    firstSubEl = el[0]
                conditionalAdd(ts, firstSubEl)
                    
                if len(el) > 1:
                    for subEl in list(el)[1:]:
                        conditionalAdd(ts, subEl)
            else:
                conditionalAdd(ts, el)

        seenArticulations = set()
        seenExpressions = set()
        
        # pylint: disable=unidiomatic-typecheck
        for n in sorted(notesToAdd.values(), key=lambda x: x.pitch.ps):
            c.add(n)
            if gatherArticulations:
                for art in n.articulations:
                    if art.tieAttach == 'first' and n.tie is not None and n.tie.type != 'start':
                        continue
                    if art.tieAttach == 'last' and n.tie is not None and n.tie.type != 'stop':
                        continue
                    
                    if gatherArticulations == 'single' and type(art) in seenArticulations:
                        continue
                    c.articulations.append(art)
                    seenArticulations.add(type(art))
            if gatherExpressions:
                for exp in n.expressions:
                    if exp.tieAttach == 'first' and n.tie is not None and n.tie.type != 'start':
                        continue
                    if exp.tieAttach == 'last' and n.tie is not None and n.tie.type != 'stop':
                        continue

                    if gatherExpressions == 'single' and type(exp) in seenExpressions:
                        continue
                    c.expressions.append(exp)
                    seenExpressions.add(type(exp))
            
        return c
Esempio n. 43
0
    def isElementOffsetInRange(self, e, offset, *, stopAfterEnd=False):
        '''
        Given an element, offset, and stream, return
        True, False, or raise StopIteration if the
        element is in the range, not in the range, or (if stopAfterEnd is True) is not
        and no future elements will be in the range.

        Factored out from __call__ to be used by OffsetHierarchyFilter and it's just
        a beast.  :-)
        '''
        if offset > self.offsetEnd:  # anything that begins after the span is definitely out
            if stopAfterEnd:
                # if sorted, optimize by breaking after exceeding offsetEnd
                # eventually we could do a binary search to speed up...
                raise StopIteration
            else:
                return False

        dur = e.duration

        elementEnd = opFrac(offset + dur.quarterLength)
        if elementEnd < self.offsetStart:
            # anything that finishes before the span ends is definitely out
            return False

        # some part of the element is at least touching some part of span.
        # all the simple cases done! Now need to filter out those that
        # are border cases depending on settings

        if dur.quarterLength == 0:
            elementIsZeroLength = True
        else:
            elementIsZeroLength = False

        if self.zeroLengthSearch is True and elementIsZeroLength is True:
            # zero Length Searches -- include all zeroLengthElements
            return True


        if self.mustFinishInSpan is True:
            if elementEnd > self.offsetEnd:
                # environLocal.warn([elementEnd, offsetEnd, e])
                return False
            if self.includeEndBoundary is False:
                # we include the end boundary if the search is zeroLength --
                # otherwise nothing can be retrieved
                if elementEnd == self.offsetEnd:
                    return False

        if self.mustBeginInSpan is True:
            if offset < self.offsetStart:
                return False
            if self.includeEndBoundary is False and offset == self.offsetEnd:
                return False
        elif (elementIsZeroLength is False
                and elementEnd == self.offsetEnd 
                and self.zeroLengthSearch is True):
            return False
                
        if self.includeEndBoundary is False and offset == self.offsetEnd:
            return False

        if self.includeElementsThatEndAtStart is False and elementEnd == self.offsetStart:
            return False

        return True
Esempio n. 44
0
    def partScoreFromSystemScore(self, systemScore):
        '''
        Take a :class:`~music21.stream.Score` object which is organized
        by Systems and return a new `Score` object which is organized by
        Parts.
        '''
        # this line is redundant currently, since all we have in systemScore
        # are Systems, but later there will be other things.
        systemStream = systemScore.getElementsByClass('System') 
        partDictById = {}
        for thisSystem in systemStream:
            # this line is redundant currently, since all we have in
            # thisSystem are Parts, but later there will be other things.
            systemOffset = thisSystem.getOffsetBySite(systemScore)
            partStream = thisSystem.getElementsByClass('Part')
            for j, thisPart in enumerate(partStream):
                if thisPart.id not in partDictById:
                    newPart = stream.Part()
                    newPart.id = thisPart.id
                    partDictById[thisPart.id] = {'part': newPart, 'number': j}
                else:
                    newPart = partDictById[thisPart.id]['part']
                for el in thisPart: # no need for recurse...
                    newPart._insertCore(common.opFrac(el.offset + systemOffset), el)
                newPart._elementsChanged()
        newScore = stream.Score()
        ## ORDERED DICT
        parts = [None for i in range(len(partDictById))]
        for partId in partDictById:
            partDict = partDictById[partId]
            parts[partDict['number']] = partDict['part']
        for p in parts:
            # remove redundant Clef and KeySignatures
            clefs = p.getElementsByClass('Clef')
            keySignatures = p.getElementsByClass('KeySignature')
            lastClef = None
            lastKeySignature = None
            for c in clefs:
                if c == lastClef:
                    p.remove(c)
                else:
                    lastClef = c
            for ks in keySignatures:
                if ks == lastKeySignature:
                    p.remove(ks)
                else:
                    lastKeySignature = ks
            p.makeMeasures(inPlace=True)
#            for m in p.getElementsByClass('Measure'):
#                barLines = m.getElementsByClass('Barline')
#                for bl in barLines:
#                    blOffset = bl.offset
#                    if blOffset == 0.0:
#                        m.remove(bl)
#                        m.leftBarline = bl
#                    elif blOffset == m.highestTime:
#                        m.remove(bl)
#                        m.rightBarline = bl # will not yet work for double repeats!
                        
            newScore._insertCore(0, p)
        newScore._elementsChanged()
        return newScore
Esempio n. 45
0
    def __call__(self, e, iterator):
        dur = e.duration
        s = iterator.srcStream
        if s is e:
            return False
        offset = s.elementOffset(e)

        #offset = common.cleanupFloat(offset)

        if offset > self.offsetEnd:  # anything that ends after the span is definitely out
            if s.isSorted:
                # if sorted, optimize by breaking after exceeding offsetEnd
                # eventually we could do a binary search to speed up...
                raise StopIteration
            else:
                return False

        elementEnd = opFrac(offset + dur.quarterLength)
        if elementEnd < self.offsetStart:
            # anything that finishes before the span ends is definitely out
            return False

        if dur.quarterLength == 0:
            elementIsZeroLength = True
        else:
            elementIsZeroLength = False


        # all the simple cases done! Now need to filter out those that
        # are border cases depending on settings

        if self.zeroLengthSearch is True and elementIsZeroLength is True:
            # zero Length Searches -- include all zeroLengthElements
            return True


        if self.mustFinishInSpan is True:
            if elementEnd > self.offsetEnd:
                #environLocal.warn([elementEnd, offsetEnd, e])
                return False
            if self.includeEndBoundary is False:
                # we include the end boundary if the search is zeroLength --
                # otherwise nothing can be retrieved
                if elementEnd == self.offsetEnd:
                    return False

        if self.mustBeginInSpan is True:
            if offset < self.offsetStart:
                return False
            if self.includeEndBoundary is False:
                if offset >= self.offsetEnd:
                    # >= is unnecessary, should just be ==, but better safe than sorry
                    return False

        if self.mustBeginInSpan is False:
            if elementIsZeroLength is False:
                if elementEnd == self.offsetEnd and self.zeroLengthSearch is True:
                    return False
        if self.includeEndBoundary is False:
            if offset >= self.offsetEnd:
                return False

        if self.includeElementsThatEndAtStart is False and elementEnd == self.offsetStart:
            return False

        return True
Esempio n. 46
0
    def getBeatFloatOrFrac(self):
        '''
        Gets the beat number as a float or fraction. Time signature independent
        
        >>> RTB = romanText.rtObjects.RTBeat
        
        Simple ones:
        
        >>> RTB('b1').getBeatFloatOrFrac()
        1.0
        >>> RTB('b2').getBeatFloatOrFrac()
        2.0
        
        etc.
        
        with easy float:
        
        >>> RTB('b1.5').getBeatFloatOrFrac()
        1.5
        >>> RTB('b1.25').getBeatFloatOrFrac()
        1.25
        
        with harder:
        
        >>> RTB('b1.33').getBeatFloatOrFrac()
        Fraction(4, 3)
        
        >>> RTB('b2.66').getBeatFloatOrFrac()
        Fraction(8, 3)
                
        >>> RTB('b1.2').getBeatFloatOrFrac()
        Fraction(6, 5)


        A third digit of .5 adds 1/2 of 1/DENOM of before.  Here DENOM is 3 (in 5/3) so
        we add 1/6 to 5/3 to get 11/6:
        

        >>> RTB('b1.66').getBeatFloatOrFrac()
        Fraction(5, 3)

        >>> RTB('b1.66.5').getBeatFloatOrFrac()
        Fraction(11, 6)


        Similarly .25 adds 1/4 of 1/DENOM... to get 21/12 or 7/4 or 1.75

        >>> RTB('b1.66.25').getBeatFloatOrFrac()
        1.75

        And .75 adds 3/4 of 1/DENOM to get 23/12
        
        >>> RTB('b1.66.75').getBeatFloatOrFrac()
        Fraction(23, 12)


        A weird way of writing 'b1.5'

        >>> RTB('b1.33.5').getBeatFloatOrFrac()
        1.5
        '''
        beatStr = self.src.replace('b', '')
        # there may be more than one decimal in the number, such as
        # 1.66.5, to show halfway through 2/3rd of a beat
        parts = beatStr.split('.')
        mainBeat = int(parts[0])
        if len(parts) > 1: # 1.66
            fracPart = common.addFloatPrecision('.' + parts[1])
        else:
            fracPart = 0.0
            
        if len(parts) > 2: # 1.66.5 
            fracPartDivisor = float('.' + parts[2]) # 0.5
            if isinstance(fracPart, float):
                fracPart = Fraction.from_float(fracPart)
            denom = fracPart.denominator
            fracBeatFrac = common.opFrac(1./(denom/fracPartDivisor))
        else:
            fracBeatFrac = 0.0

        if len(parts) > 3:
            environLocal.printDebug(['got unexpected beat: %s' % self.src])
            raise RTTokenException('cannot handle specification: %s' %  self.src)
            
            
        beat = common.opFrac(mainBeat + fracPart + fracBeatFrac)
        return beat
Esempio n. 47
0
def makeTies(
    s,
    meterStream=None,
    inPlace=True,
    displayTiedAccidentals=False,
    ):
    '''
    Given a stream containing measures, examine each element in the
    Stream. If the elements duration extends beyond the measure's boundary,
    create a tied entity, placing the split Note in the next Measure.

    Note that this method assumes that there is appropriate space in the
    next Measure: this will not shift Note objects, but instead allocate
    them evenly over barlines. Generally, makeMeasures is called prior to
    calling this method.

    If `inPlace` is True, this is done in-place;
    if `inPlace` is False, this returns a modified deep copy.

    Put a 12-quarter-note-long note into a Stream w/ 4/4 as the duration.

    >>> d = stream.Stream()
    >>> d.insert(0, meter.TimeSignature('4/4'))
    >>> n = note.Note('C4')
    >>> n.quarterLength = 12
    >>> d.insert(0, n)
    >>> d.show('text')
    {0.0} <music21.meter.TimeSignature 4/4>
    {0.0} <music21.note.Note C>

    After running makeMeasures, we get nice measures, a clef, but only one
    way-too-long note in Measure 1:
    
    >>> x = d.makeMeasures()
    >>> x.show('text')
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.clef.TrebleClef>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.note.Note C>
    {4.0} <music21.stream.Measure 2 offset=4.0>
    <BLANKLINE>
    {8.0} <music21.stream.Measure 3 offset=8.0>
        {0.0} <music21.bar.Barline style=final>
    >>> n2 = x.measure(1).notes[0]
    >>> n2.duration.quarterLength
    12.0    
    >>> n2 is n
    False
    
    But after running makeTies, all is good:
    
    >>> x.makeTies(inPlace=True)
    >>> x.show('text')
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.clef.TrebleClef>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.note.Note C>
    {4.0} <music21.stream.Measure 2 offset=4.0>
        {0.0} <music21.note.Note C>
    {8.0} <music21.stream.Measure 3 offset=8.0>
        {0.0} <music21.note.Note C>
        {4.0} <music21.bar.Barline style=final>
    >>> m = x.measure(1).notes[0]
    >>> m.duration.quarterLength
    4.0
    >>> m is n
    False
    >>> m.tie
    <music21.tie.Tie start>
    >>> x.measure(2).notes[0].tie
    <music21.tie.Tie continue>
    >>> x.measure(3).notes[0].tie
    <music21.tie.Tie stop>
        
    Same experiment, but with rests:
    
    >>> d = stream.Stream()
    >>> d.insert(0, meter.TimeSignature('4/4'))
    >>> r = note.Rest()
    >>> r.quarterLength = 12
    >>> d.insert(0, r)
    >>> x = d.makeMeasures()
    >>> x.makeTies(inPlace = True)
    >>> x.show('text')
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.clef.TrebleClef>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.note.Rest rest>
    {4.0} <music21.stream.Measure 2 offset=4.0>
        {0.0} <music21.note.Rest rest>
    {8.0} <music21.stream.Measure 3 offset=8.0>
        {0.0} <music21.note.Rest rest>
        {4.0} <music21.bar.Barline style=final>        

    Notes: uses base.Music21Object.splitAtQuarterLength() once it has figured out
    what to split.

    OMIT_FROM_DOCS
    TODO: inPlace should be False
    TODO: take a list of clases to act as filter on what elements are tied.

    configure ".previous" and ".next" attributes
    '''
    from music21 import stream

    #environLocal.printDebug(['calling Stream.makeTies()'])

    if not inPlace:  # make a copy
        returnObj = copy.deepcopy(s)
    else:
        returnObj = s
    if len(returnObj) == 0:
        raise stream.StreamException('cannot process an empty stream')

    # get measures from this stream
    measureStream = returnObj.getElementsByClass('Measure')
    if len(measureStream) == 0:
        raise stream.StreamException(
            'cannot process a stream without measures')

    #environLocal.printDebug([
    #    'makeTies() processing measureStream, length', measureStream,
    #    len(measureStream)])

    # may need to look in activeSite if no time signatures are found
    # presently searchContext is False to save time
    if meterStream is None:
        meterStream = returnObj.getTimeSignatures(sortByCreationTime=True,
                        searchContext=False)

    mCount = 0
    lastTimeSignature = None
    while True:
        # update measureStream on each iteration,
        # as new measure may have been added to the returnObj stream
        measureStream = returnObj.getElementsByClass('Measure')
        if mCount >= len(measureStream):
            break  # reached the end of all measures available or added
        # get the current measure to look for notes that need ties
        m = measureStream[mCount]
        if m.timeSignature is not None:
            lastTimeSignature = m.timeSignature

        # get next measure; we may not need it, but have it ready
        if mCount + 1 < len(measureStream):
            mNext = measureStream[mCount + 1]
            mNextAdd = False  # already present; do not append
        else:  # create a new measure
            mNext = stream.Measure()
            # set offset to last offset plus total length
            moffset = measureStream.elementOffset(m)
            if lastTimeSignature is not None:
                mNext.offset = (moffset +
                                lastTimeSignature.barDuration.quarterLength)
            else:
                mNext.offset = moffset
            if len(meterStream) == 0:  # in case no meters are defined
                ts = meter.TimeSignature()
                ts.load('%s/%s' % (defaults.meterNumerator,
                    defaults.meterDenominatorBeatType))
            else:  # get the last encountered meter
                ts = meterStream.getElementAtOrBefore(mNext.offset)
            # only copy and assign if not the same as the last
            if (lastTimeSignature is not None and
                    not lastTimeSignature.ratioEqual(ts)):
                mNext.timeSignature = copy.deepcopy(ts)
            # increment measure number
            mNext.number = m.number + 1
            mNextAdd = True  # new measure, needs to be appended

        if mNext.hasVoices():
            mNextHasVoices = True
        else:
            mNextHasVoices = False

        #environLocal.printDebug([
        #    'makeTies() dealing with measure', m, 'mNextAdd', mNextAdd])
        # for each measure, go through each element and see if its
        # duraton fits in the bar that contains it

        # if there are voices, we must look at voice id values to only
        # connect ties to components in the same voice, assuming there
        # are voices in the next measure
        try:
            mEnd = lastTimeSignature.barDuration.quarterLength
        except AttributeError:
            ts = m.getContextByClass('TimeSignature')
            if ts is not None:
                lastTimeSignature = ts
                mEnd = lastTimeSignature.barDuration.quarterLength
            else:
                mEnd = 4.0  # Default
        if m.hasVoices():
            bundle = m.voices
            mHasVoices = True
        else:
            bundle = [m]
            mHasVoices = False
        # bundle components may be voices, or just a measure
        for v in bundle:
            for e in v:
                #environLocal.printDebug([
                #    'Stream.makeTies() iterating over elements in measure',
                #    m, e])
                #if hasattr(e, 'duration') and e.duration is not None:
                if e.duration is not None:
                    # check to see if duration is within Measure
                    eOffset = v.elementOffset(e)
                    eEnd = opFrac(eOffset + e.duration.quarterLength)
                    # assume end can be at boundary of end of measure
                    overshot = eEnd - mEnd

                    if overshot > 0:
                        if eOffset >= mEnd:
                            continue # skip elements that extend past measure boundary.
#                             raise stream.StreamException(
#                                 'element (%s) has offset %s within a measure '
#                                 'that ends at offset %s' % (e, eOffset, mEnd))

                        qLenBegin = mEnd - eOffset
                        e, eRemain = e.splitAtQuarterLength(qLenBegin,
                            retainOrigin=True,
                            displayTiedAccidentals=displayTiedAccidentals)

                        # manage bridging voices
                        if mNextHasVoices:
                            if mHasVoices:  # try to match voice id
                                dst = mNext.voices[v.id]
                            # src does not have voice, but dst does
                            else:  # place in top-most voice
                                dst = mNext.voices[0]
                        else:
                            # mNext has no voices but this one does
                            if mHasVoices:
                                # internalize all components in a voice
                                mNext.internalize(container=stream.Voice)
                                # place in first voice
                                dst = mNext.voices[0]
                            else:  # no voices in either
                                dst = mNext

                        #eRemain.activeSite = mNext
                        # manually set activeSite
                        # cannot use _insertCore here
                        dst.insert(0, eRemain)

                        # we are not sure that this element fits
                        # completely in the next measure, thus, need to
                        # continue processing each measure
                        if mNextAdd:
                            #environLocal.printDebug([
                            #    'makeTies() inserting mNext into returnObj',
                            #    mNext])
                            returnObj.insert(mNext.offset, mNext)
                    elif overshot > 0:
                        environLocal.printDebug([
                            'makeTies() found and skipping extremely small '
                            'overshot into next measure', overshot])
        mCount += 1
    del measureStream  # clean up unused streams
    # changes elements
    returnObj.elementsChanged()
    if not inPlace:
        return returnObj
    else:
        return None