Beispiel #1
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
Beispiel #2
0
def makeTupletBrackets(s: m21.stream.Stream,
                       inPlace=False) -> m21.stream.Stream:
    returnObj = s if inPlace else copy.deepcopy(s)
    durationList = [
        n.duration for n in returnObj.notesAndRests
        if n.duration.quarterLength > 0
    ]
    if not durationList:
        logger.info(
            f"No notes or rests to make tuplet brackets on stream: {s}")
        return returnObj
    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:
            logger.warning(
                '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]
        tupletPrevious = tupletMap[i - 1][0] if i > 0 else None
        tupletNext = tupletMap[i + 1][0] if i < len(tupletMap) - 1 else None
        if tupletObj is not None:
            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'
                    completionTarget = tupletObj.totalTupletLength()
                    # 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
            elif tupletPrevious is not None and tupletNext is not None:
                # do not need to change tuplet type; should be None
                pass
    return returnObj
Beispiel #3
0
def correlateHarmonies(currentMapping, music21Part):
    # noinspection PyShadowingNames
    '''
    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.flatten().notesAndRests.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
Beispiel #4
0
    def calculateOrnamentNoteQl(self, busyNotes, simpleNotes=None):
        '''
        Finds the quarter length value for each ornament note
        assuming busy notes all are an expanded ornament.

        Expanded ornament total duration is time of all busy notes combined or
        duration of the first note in simpleNotes when provided.
        '''
        numOrnamentNotes = len(busyNotes)
        totalDurationQuarterLength = self.calculateOrnamentTotalQl(
            busyNotes, simpleNotes)
        return opFrac(totalDurationQuarterLength / numOrnamentNotes)
 def calculateOrnamentTotalQl(
         self,
         busyNotes: List[note.GeneralNote],
         simpleNotes: Optional[List[note.GeneralNote]] = None):
     '''
     Returns total length of trill assuming busy notes are all an expanded trill.
     This is either the time of all busy notes combined or
     duration of the first note in simpleNotes when provided.
     '''
     if simpleNotes:
         return simpleNotes[0].duration.quarterLength
     trillQl = 0
     for n in busyNotes:
         trillQl += float(n.duration.quarterLength)
     return opFrac(trillQl)
Beispiel #6
0
    def coreSetElementOffset(self,
                             element: Music21Object,
                             offset: t.Union[int, float, Fraction,
                                             OffsetSpecial],
                             *,
                             addElement=False,
                             setActiveSite=True):
        '''
        Sets the Offset for an element, very quickly.
        Caller is responsible for calling :meth:`~music21.stream.core.coreElementsChanged`
        afterward.

        >>> s = stream.Stream()
        >>> s.id = 'Stream1'
        >>> n = note.Note('B-4')
        >>> s.insert(10, n)
        >>> n.offset
        10.0
        >>> s.coreSetElementOffset(n, 20.0)
        >>> n.offset
        20.0
        >>> n.getOffsetBySite(s)
        20.0
        '''
        # Note: not documenting 'highestTime' is on purpose, since can only be done for
        # elements already stored at end.  Infinite loop.
        try:
            offset = opFrac(offset)
        except TypeError:
            if offset not in OffsetSpecial:  # pragma: no cover
                raise StreamException(
                    f'Cannot set offset to {offset!r} for {element}')

        idEl = id(element)
        if not addElement and idEl not in self._offsetDict:
            raise StreamException(
                f'Cannot set the offset for element {element}, not in Stream {self}.'
            )
        self._offsetDict[idEl] = (offset, element)  # fast
        if setActiveSite:
            self.coreSelfActiveSite(element)
Beispiel #7
0
    def isElementOffsetInRange(self, e, offset, *, stopAfterEnd=False) -> bool:
        '''
        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
            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
Beispiel #8
0
def makeBeams(s: m21.stream.Stream, *, inPlace=False) -> m21.stream.Stream:
    returnObj = s if inPlace else copy.deepcopy(s)
    mColl: List[m21.stream.Measure]
    if 'Measure' in s.classes:
        mColl = [returnObj]  # store a list of measures for processing
    else:
        mColl = list(
            returnObj.iter.getElementsByClass('Measure'))  # a list of measures
        if not mColl:
            raise m21.stream.StreamException(
                'Cannot process a stream that is neither a Measure nor has no 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:
            raise m21.stream.StreamException(
                'cannot process beams in a Measure without a time signature')
        noteGroups = []
        if m.hasVoices():
            for v in m.voices:
                noteGroups.append(v.notesAndRests.stream())
        else:
            noteGroups.append(m.notesAndRests.stream())

        for noteStream in noteGroups:
            if len(noteStream) <= 1:
                continue  # nothing to beam
            realNotes = [n for n in noteStream if n.duration.quarterLength > 0]
            durList = [n.duration for n in realNotes]
            # error check; call before sending to time signature, as, if this
            # fails, it represents a problem that happens before time signature
            # processing
            summed = sum([d.quarterLength for d in durList])
            durSum = opFrac(opFrac(
                summed))  # the double call corrects for tiny errors in adding

            # floats and Fractions in the sum() call -- the first opFrac makes it
            # impossible to have 4.00000000001, but returns Fraction(4, 1). The
            # second call converts Fraction(4, 1) to 4.0
            barQuarterLength = lastTimeSignature.barDuration.quarterLength
            if durSum > barQuarterLength:
                continue

            # getBeams
            offset = 0.0
            if m.paddingLeft != 0.0:
                offset = opFrac(m.paddingLeft)
            elif noteStream.highestTime < barQuarterLength:
                offset = barQuarterLength - noteStream.highestTime

            beamsList = lastTimeSignature.getBeams(realNotes,
                                                   measureStartOffset=offset)
            for n, beams in zip(realNotes, beamsList):
                n.beams = beams if beams is not None else m21.beam.Beams()

    del mColl  # remove Stream no longer needed

    returnObj.streamStatus.beams = True
    return returnObj