Beispiel #1
0
    def _checkRestForVerticalPositioning(rest: HumdrumToken,
                                         baseline: int) -> bool:
        m = re.search(r'([A-Ga-g]+)', rest.text)
        if m is None:
            return False

        pitch: str = m.group(1)
        b7: int = Convert.kernToBase7(pitch)
        if b7 < 0:
            # that wasn't really a pitch, no vertical positioning for you
            return False

        diff: int = (b7 - baseline) + 100
        if diff % 2 != 0:
            # force to every other diatonic step (staff lines)
            if rest.duration > 1:
                b7 -= 1
            else:
                b7 += 1

        # Instead of ploc and oloc for MEI (which humlib does), compute and save what the
        # stepShift for a music21 rest should be.
        # stepShift = 0 means "on the middle line", -1 means "in the first space below the
        # midline", +2 means "on the line above the midline", etc.
        # baseline is the base7 pitch of the lowest line in the staff -> stepShift = -4
        # b7 is the base7 pitch (including octave) of where the rest should go, so:

        # midline is 2 spaces + 2 lines (4 diatonic steps) above baseline
        midline: int = baseline + 4
        stepShift: int = b7 - midline
        rest.setValue('auto', 'stepShift', str(stepShift))

        return True
    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))
Beispiel #3
0
    def transferSidesFromStaff(line: HumdrumLine, staff: GridStaff,
                               emptyStr: str, maxxcount: int, maxdcount: int,
                               maxvcount: int):
        sides: GridSide = staff.sides
        vcount: int = sides.verseCount

        # XMLID
        if maxxcount > 0:
            xmlId: HumdrumToken = sides.xmlId
            if xmlId is not None:
                line.appendToken(xmlId)
            else:
                line.appendToken(HumdrumToken(emptyStr))

        # DYNAMICS
        if maxdcount > 0:
            dynamics: HumdrumToken = sides.dynamics
            if dynamics is not None:
                line.appendToken(dynamics)
            else:
                line.appendToken(HumdrumToken(emptyStr))

        # VERSES
        for i in range(0, vcount):
            verse: HumdrumToken = sides.getVerse(i)
            if verse is not None:
                line.appendToken(verse)
            else:
                line.appendToken(HumdrumToken(emptyStr))

        for i in range(vcount, maxvcount):
            line.appendToken(HumdrumToken(emptyStr))
Beispiel #4
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
    def addLayoutParameter(self, associatedSlice: GridSlice,
                           partIndex: int, staffIndex: int, voiceIndex: int,
                           locomment: str) -> None:
        # add this '!LO:' string just before this associatedSlice
        if len(self.slices) == 0:
            # something strange happened: expecting at least one item in measure.
            # associatedSlice is supposed to already be in the measure.
            return

        associatedSliceIdx: t.Optional[int] = None
        if associatedSlice is None:
            # place at end of measure (associate with imaginary slice just off the end)
            associatedSliceIdx = len(self.slices)
        else:
            # find owning line (associatedSlice)
            foundIt: bool = False
            for associatedSliceIdx in range(len(self.slices) - 1, -1, -1):
                gridSlice: GridSlice = self.slices[associatedSliceIdx]
                if gridSlice is associatedSlice:
                    foundIt = True
                    break
            if not foundIt:
                # cannot find owning line (a.k.a. associatedSlice is not in this GridMeasure)
                return

        # see if the previous slice is a layout slice we can use
        prevIdx: int = associatedSliceIdx - 1
        prevSlice: GridSlice = self.slices[prevIdx]
        if prevSlice.isLocalLayoutSlice:
            prevStaff: GridStaff = prevSlice.parts[partIndex].staves[staffIndex]
            prevVoice: GridVoice = self._getIndexedVoice_AppendingIfNecessary(prevStaff.voices,
                                                                              voiceIndex)
            if prevVoice.token is None or prevVoice.token.text == '!':
                prevVoice.token = HumdrumToken(locomment)
                return

        # if we get here, we couldn't use the previous slice, so we need to insert
        # a new Layout slice to use, just before the associated slice.
        insertPoint: int = associatedSliceIdx
        newSlice: GridSlice

        if associatedSlice is not None:
            newSlice = GridSlice(self, associatedSlice.timestamp, SliceType.Layouts)
            newSlice.initializeBySlice(associatedSlice)
            self.slices.insert(insertPoint, newSlice)
        else:
            newSlice = GridSlice(self, self.timestamp + self.duration, SliceType.Layouts)
            newSlice.initializeBySlice(self.slices[-1])
            self.slices.append(newSlice)

        newStaff: GridStaff = newSlice.parts[partIndex].staves[staffIndex]
        newVoice: GridVoice = self._getIndexedVoice_AppendingIfNecessary(newStaff.voices,
                                                                         voiceIndex)
        newVoice.token = HumdrumToken(locomment)
    def addToken(self, tok: t.Union[HumdrumToken, str], parti: int,
                 staffi: int, voicei: int) -> None:
        if isinstance(tok, str):
            tok = HumdrumToken(tok)

        if not 0 <= parti < len(self.parts):
            raise HumdrumInternalError(
                f'Error: part index {parti} is out of range(0, {len(self.parts)})'
            )

        if staffi < 0:
            raise HumdrumInternalError(f'Error: staff index {staffi} < 0')

        part: GridPart = self.parts[parti]

        # fill in enough staves to get you to staffi
        if staffi >= len(part.staves):
            for _ in range(len(part.staves), staffi + 1):
                part.staves.append(GridStaff())

        staff: GridStaff = part.staves[staffi]

        # fill in enough voices to get you to voicei
        if voicei >= len(staff.voices):
            for _ in range(len(staff.voices), voicei + 1):
                staff.voices.append(GridVoice())

        voice: t.Optional[GridVoice] = staff.voices[voicei]
        if t.TYPE_CHECKING:
            # because we just filled staff.voices[voicei] in with a GridVoice if necessary
            assert isinstance(voice, GridVoice)

        # Ok, finally do what you came to do...
        voice.token = tok
    def dataType(self):  # -> HumdrumToken
        if self._dataTypeTokenCached is not None:
            return self._dataTypeTokenCached

        from converter21.humdrum import HumdrumToken
        if self.ownerLine is None:
            return HumdrumToken('')

        tok = self.ownerLine.trackStart(self.track)
        if tok is None:
            return HumdrumToken('')

        # cache it
        self._dataTypeTokenCached = tok

        return tok
Beispiel #8
0
    def addToken(self, tok: Union[HumdrumToken, str], parti: int, staffi: int,
                 voicei: int):
        if isinstance(tok, str):
            tok = HumdrumToken(tok)

        if not 0 <= parti < len(self.parts):
            raise HumdrumInternalError(
                f'Error: part index {parti} is out of range(0, {len(self.parts)})'
            )

        if staffi < 0:
            raise HumdrumInternalError(f'Error: staff index {staffi} < 0')

        part: GridPart = self.parts[parti]

        # fill in enough staves to get you to staffi
        if staffi >= len(part.staves):
            for _ in range(len(part.staves), staffi + 1):
                part.staves.append(GridStaff())

        staff: GridStaff = part.staves[staffi]

        # fill in enough voices to get you to voicei
        if voicei >= len(staff.voices):
            for _ in range(len(staff.voices), voicei + 1):
                staff.voices.append(GridVoice())

        voice: GridVoice = staff.voices[voicei]

        # Ok, finally do what you came to do...
        voice.token = tok
Beispiel #9
0
 def appendToken(self,
                 token,
                 tabCount: int = 0):  # token can be HumdrumToken or str
     if isinstance(token, str):
         token = HumdrumToken(token)
     self._tokens.append(token)
     self._numTabsAfterToken.append(tabCount)
Beispiel #10
0
    def token(self, newToken: Union[HumdrumToken, str]):
        if isinstance(newToken, HumdrumToken) or newToken is None:
            self._token = newToken
        elif isinstance(newToken, str):
            self._token = HumdrumToken(newToken)
        else:
            raise HumdrumInternalError(f'invalid type of token: {newToken}')

        self._isTransfered = False
Beispiel #11
0
 def insertToken(self, index: int, token,
                 tabCount: int):  # token can be HumdrumToken or str
     if isinstance(token, HumdrumToken):
         self._tokens.insert(index, token)
         self._numTabsAfterToken.insert(index, tabCount)
         return
     if isinstance(token, str):
         self._tokens.insert(index, HumdrumToken(token))
         self._numTabsAfterToken.insert(index, tabCount)
Beispiel #12
0
    def createTokensFromLine(self) -> int:  # returns number of tokens created
        '''
        // delete previous tokens (will need to re-analyze structure
        // of file after this).
        '''
        self._tokens = []
        self._numTabsAfterToken = []

        if self.text == '':
            # one empty token
            token = HumdrumToken()
            token.ownerLine = self
            self._tokens = [token]
            self._numTabsAfterToken = [0]
            return 1

        if self.text.startswith('!!'):
            # global, so just one token for the whole line
            token = HumdrumToken(self.text)
            token.ownerLine = self
            self._tokens = [token]
            self._numTabsAfterToken = [0]
            return 1

        # tokenStrList: [str] = self.text.split('\t')
        # for tokenStr in tokenStrList:
        #     token = HumdrumToken(tokenStr)
        #     token.ownerLine = self
        #     self._tokens.append(token)
        #     self._numTabsAfterToken.append(1)

        for m in re.finditer(r'([^\t]+)(\t*)', self.text):
            # m is a match object containing two groups: first the token, then any trailing tabs
            tokenStr = m.group(1)
            if tokenStr is None:
                break

            tabsStr = m.group(2)
            if tabsStr is None:
                numTabsAfterThisToken = 0
            else:
                numTabsAfterThisToken = len(tabsStr)

            token = HumdrumToken(tokenStr)
            token.ownerLine = self
            self._tokens.append(token)
            self._numTabsAfterToken.append(numTabsAfterThisToken)

        return len(self._tokens)
Beispiel #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
Beispiel #14
0
    def addDynamicsLayoutParameters(self, associatedSlice: GridSlice,
                                    partIndex: int, staffIndex: int,
                                    locomment: str):
        if len(self.slices) == 0:
            # something strange happened: expecting at least one item in measure.
            return  # associatedSlice is supposed to already be in the measure

        # find owning line (associatedSlice)
        foundIt: bool = False
        associatedSliceIdx: int = None
        for associatedSliceIdx in range(len(self.slices) - 1, -1,
                                        -1):  # loop in reverse index order
            gridSlice: GridSlice = self.slices[associatedSliceIdx]
            if gridSlice is associatedSlice:
                foundIt = True
                break
        if not foundIt:
            # cannot find owning line (a.k.a. associatedSlice is not in this GridMeasure)
            return

        # see if the previous slice is a layout slice we can use
        prevIdx: int = associatedSliceIdx - 1
        prevSlice: GridSlice = self.slices[prevIdx]
        if prevSlice.isLocalLayoutSlice:
            prevStaff: GridStaff = prevSlice.parts[partIndex].staves[
                staffIndex]
            if prevStaff.dynamics is None:
                prevStaff.dynamics = HumdrumToken(locomment)
                return

        # if we get here, we couldn't use the previous slice, so we need to insert
        # a new Layout slice to use, just before the associated slice.
        insertPoint: int = associatedSliceIdx
        newSlice: GridSlice = GridSlice(self, associatedSlice.timestamp,
                                        SliceType.Layouts)
        newSlice.initializeBySlice(associatedSlice)
        self.slices.insert(insertPoint, newSlice)

        newStaff: GridStaff = newSlice.parts[partIndex].staves[staffIndex]
        newStaff.dynamics = HumdrumToken(locomment)
    def copyStructure(self, fromLine: 'HumdrumLine', nullStr: str) -> None:
        for fromToken in fromLine.tokens():
            newToken: HumdrumToken = HumdrumToken(nullStr)
            newToken.ownerLine = self
            newToken.copyStructure(fromToken)
            self._tokens.append(newToken)

        self.createLineFromTokens()
        # pylint: disable=protected-access
        self._numTabsAfterToken = fromLine._numTabsAfterToken
        self._rhythmAnalyzed = fromLine._rhythmAnalyzed
        # pylint: enable=protected-access
        self.ownerFile = fromLine.ownerFile
Beispiel #16
0
    def __init__(self,
                 token: Union[HumdrumToken, str] = None,
                 duration: HumNum = HumNum(0)):
        self._token: HumdrumToken = None
        if isinstance(token, HumdrumToken) or token is None:
            self._token = token
        elif isinstance(token, str):
            self._token = HumdrumToken(token)
        else:
            raise HumdrumInternalError(f'invalid type of token: {token}')

        self._nextDur = duration
        #         self._prevDur = HumNum(0) # appears to be unused (never set to anything but zero)
        self._isTransfered: bool = False
Beispiel #17
0
    def transferSidesFromPart(line: HumdrumLine, part: GridPart, emptyStr: str,
                              maxhcount: int, maxfcount: int):
        sides: GridSide = part.sides
        hcount: int = sides.harmonyCount

        # FIGURED BASS
        if maxfcount > 0:
            figuredBass: HumdrumToken = sides.figuredBass
            if figuredBass is not None:
                line.appendToken(figuredBass)
            else:
                line.appendToken(HumdrumToken(emptyStr))

        # HARMONY
        for _ in range(0, hcount):
            harmony: HumdrumToken = sides.harmony
            if harmony is not None:
                line.appendToken(harmony)
            else:
                line.appendToken(HumdrumToken(emptyStr))

        for _ in range(hcount, maxhcount):
            line.appendToken(HumdrumToken(emptyStr))
Beispiel #18
0
    def _createRecipTokenFromDuration(duration: HumNum) -> HumdrumToken:
        duration /= 4  # convert to quarter note units

        if duration.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 duration.numerator == 1:
            return HumdrumToken(str(duration.denominator))

        if duration.numerator % 3 == 0:
            dotdur: HumNum = (duration * 2) / 3
            if dotdur.numerator == 1:
                return HumdrumToken(str(dotdur.denominator) + '.')

        # try to fit to two dots here

        # try to fit to three dots here

        return HumdrumToken(
            str(duration.denominator) + '%' + str(duration.numerator))
Beispiel #19
0
    def setVerse(self, index: int, token: Union[HumdrumToken, str]):
        if isinstance(token, str):
            # make it into a proper token
            token = HumdrumToken(token)

        if index == self.verseCount:
            self._verses.append(token)
        elif index < self.verseCount:
            # Insert in a slot which might already have a verse token
            self._verses[index] = token
        else:
            # add more than one verse spot, and insert verse:
            for _ in range(self.verseCount,
                           index + 1):  # verseCount through index, inclusive
                self._verses.append(None)
            self._verses[index] = token
Beispiel #20
0
    def setNullTokenLayer(self, layerIndex: int, sliceType: SliceType,
                          nextDur: HumNum):
        if sliceType == SliceType.Invalid:
            return
        if sliceType == SliceType.GlobalLayouts:
            return
        if sliceType == SliceType.GlobalComments:
            return
        if sliceType == SliceType.ReferenceRecords:
            return

        nullStr: str = ''
        if sliceType < SliceType.Data_:
            nullStr = '.'
        elif sliceType <= SliceType.Measure_:
            nullStr = '='
        elif sliceType <= SliceType.Interpretation_:
            nullStr = '*'
        elif sliceType <= SliceType.Spined_:
            nullStr = '!'
        else:
            raise HumdrumInternalError(
                f'!!STRANGE ERROR: {self}, SLICE TYPE: {sliceType}')

        if layerIndex < len(self.voices):
            if (self.voices[layerIndex] is not None
                    and self.voices[layerIndex].token is not None):
                if self.voices[layerIndex].token.text == nullStr:
                    # there is already a null data token here, so don't
                    # replace it.
                    return
                raise HumdrumExportError(
                    'Warning, existing token: \'{self.voices[layerIndex].token.text}\' where a null token should be.'
                )

        token: HumdrumToken = HumdrumToken(nullStr)
        self.setTokenLayer(layerIndex, token, nextDur)
Beispiel #21
0
    def _linkSlurOrPhraseEndpoints(slurOrPhrase: str, startTok: HumdrumToken,
                                   endTok: HumdrumToken) -> None:
        if slurOrPhrase == HumdrumToken.SLUR:
            prefix = 'slur'
        else:
            prefix = 'phrase'

        durTag: str = prefix + 'Duration'
        endTag: str = prefix + 'EndId'
        startTag: str = prefix + 'StartId'
        startNumberTag: str = prefix + 'StartNumber'
        endNumberTag: str = prefix + 'EndNumber'
        startCountTag: str = prefix + 'StartCount'
        endCountTag: str = prefix + 'EndCount'

        startCount: int = startTok.getValueInt('auto', startCountTag) + 1
        openCount: int = startTok.text.count(slurOrPhrase)
        openEnumeration = openCount - startCount + 1

        if openEnumeration > 1:
            openSuffix: str = str(openEnumeration)
            endTag += openSuffix
            durTag += openSuffix

        endCount: int = endTok.getValueInt('auto', endCountTag) + 1
        closeEnumeration: int = endCount
        if closeEnumeration > 1:
            closeSuffix: str = str(closeEnumeration)
            startTag += closeSuffix
            startNumberTag += closeSuffix

        duration: HumNum = opFrac(endTok.durationFromStart -
                                  startTok.durationFromStart)

        startTok.setValue('auto', endTag, endTok)
        startTok.setValue('auto', 'id', startTok)
        startTok.setValue('auto', endNumberTag, closeEnumeration)
        startTok.setValue('auto', durTag, duration)
        startTok.setValue('auto', startCountTag, startCount)

        endTok.setValue('auto', startTag, startTok)
        endTok.setValue('auto', 'id', endTok)
        endTok.setValue('auto', startNumberTag, openEnumeration)
        endTok.setValue('auto', endCountTag, endCount)
Beispiel #22
0
    def token(self, newToken: t.Optional[t.Union[HumdrumToken, str]]) -> None:
        if isinstance(newToken, str):
            newToken = HumdrumToken(newToken)
        self._token = newToken

        self._isTransfered = False
Beispiel #23
0
def CheckHumdrumToken( token: HumdrumToken,
                        expectedText: str = '',
                        expectedDataType: str = '',
                        expectedTokenType: str = TOKENTYPE_DATA,
                        expectedSpecificType: str = SPECIFICTYPE_NOTHINGSPECIFIC,
                        expectedDuration: str = HumNum(-1)
                        ):

    #print('CheckHumdrumToken: token = "{}"'.format(token))

    # set up some derived expectations
    expectedIsData = expectedTokenType == TOKENTYPE_DATA
    expectedIsBarline = expectedTokenType == TOKENTYPE_BARLINE
    expectedIsInterpretation = expectedTokenType == TOKENTYPE_INTERPRETATION
    expectedIsLocalComment = expectedTokenType == TOKENTYPE_LOCALCOMMENT
    expectedIsGlobalComment = expectedTokenType == TOKENTYPE_GLOBALCOMMENT
#     expectedIsGlobalReference = expectedTokenType == TOKENTYPE_GLOBALREFERENCE
#     expectedIsUniversalComment = expectedTokenType == TOKENTYPE_UNIVERSALCOMMENT
#     expectedIsUniversalReference = expectedTokenType == TOKENTYPE_UNIVERSALREFERENCE

    expectedIsNote = expectedSpecificType == SPECIFICTYPE_NOTE
    expectedIsRest = expectedSpecificType == SPECIFICTYPE_REST
    expectedIsNullData = expectedSpecificType == SPECIFICTYPE_NULLDATA
    expectedIsNullInterpretation = expectedSpecificType == SPECIFICTYPE_NULLINTERPRETATION
    expectedIsNullComment = expectedSpecificType == SPECIFICTYPE_NULLCOMMENT
    expectedIsNull = expectedIsNullData or expectedIsNullInterpretation or expectedIsNullComment

    expectedIsKeySignature = expectedSpecificType == SPECIFICTYPE_KEYSIGNATURE
    expectedIsTimeSignature = expectedSpecificType == SPECIFICTYPE_TIMESIGNATURE
    expectedIsClef = expectedSpecificType == SPECIFICTYPE_CLEF
    expectedIsSplitInterpretation = expectedSpecificType == SPECIFICTYPE_SPLIT
    expectedIsMergeInterpretation = expectedSpecificType == SPECIFICTYPE_MERGE
    expectedIsExchangeInterpretation = expectedSpecificType == SPECIFICTYPE_EXCHANGE
    expectedIsAddInterpretation = expectedSpecificType == SPECIFICTYPE_ADD
    expectedIsTerminateInterpretation = expectedSpecificType == SPECIFICTYPE_TERMINATE
    expectedIsExclusiveInterpretation = expectedSpecificType == SPECIFICTYPE_EXINTERP
    expectedIsManipulator = expectedIsSplitInterpretation \
                                or expectedIsMergeInterpretation \
                                or expectedIsExchangeInterpretation \
                                or expectedIsAddInterpretation \
                                or expectedIsTerminateInterpretation \
                                or expectedIsExclusiveInterpretation

    expectedIsKern = expectedDataType == '**kern'
    expectedIsMens = expectedDataType == '**mens'
    expectedIsRecip = expectedDataType == '**recip'
    expectedIsStaffDataType = expectedIsKern or expectedIsMens

    # text
    assert token.text == expectedText
    assert str(token) == expectedText

    # duration
    assert token.duration == expectedDuration
    assert token.scaledDuration(HumNum(1,5)) == expectedDuration * HumNum(1,5)

    # Token Type
    assert token.isData == expectedIsData
    assert token.isBarline == expectedIsBarline
    assert token.isInterpretation == expectedIsInterpretation
    assert token.isLocalComment == expectedIsLocalComment
    assert token.isGlobalComment == expectedIsGlobalComment
#     assert token.isGlobalReference == expectedIsGlobalReference
#     assert token.isUniversalComment == expectedIsUniversalComment
#     assert token.isUniversalReference == expectedIsUniversalReference

    # Specific Type
    assert token.isNullData == expectedIsNullData
    assert token.isNull == expectedIsNull
    assert token.isNote == expectedIsNote
    assert token.isRest == expectedIsRest
    assert token.isKeySignature == expectedIsKeySignature
    assert token.isTimeSignature == expectedIsTimeSignature
    assert token.isClef == expectedIsClef
    assert token.isSplitInterpretation == expectedIsSplitInterpretation
    assert token.isMergeInterpretation == expectedIsMergeInterpretation
    assert token.isExchangeInterpretation == expectedIsExchangeInterpretation
    assert token.isAddInterpretation == expectedIsAddInterpretation
    assert token.isTerminateInterpretation == expectedIsTerminateInterpretation
    assert token.isExclusiveInterpretation == expectedIsExclusiveInterpretation
    assert token.isManipulator == expectedIsManipulator

    # Data Type
    assert token.dataType.text == expectedDataType
    assert token.isDataType(expectedDataType) == True
    if expectedDataType[:2] == '**':
        assert token.isDataType(expectedDataType[1:]) == False
        assert token.isDataType(expectedDataType[2:]) == True
    assert token.isKern == expectedIsKern
    assert token.isMens == expectedIsMens
    assert token.isStaffDataType == expectedIsStaffDataType
Beispiel #24
0
    def expandTremolo(self, token: HumdrumToken):
        value: int = 0
        addBeam: bool = False
        tnotes: int = -1

        m = re.search(r'@(\d+)@', token.text)
        if not m:
            return

        value = int(m.group(1))
        duration: HumNum = Convert.recipToDuration(token.text)
        count: HumNum = HumNum(duration * value / 4)
        if count.denominator != 1:
            print(f'Error: non-integer number of tremolo notes: {token}',
                  file=sys.stderr)
            return
        if value < 8:
            print(
                f'Error: tremolo notes can only be eighth-notes or shorter: {token}',
                file=sys.stderr)
            return
        if float(duration) > 0.5:
            # needs to be less than one for tuplet quarter note tremolos
            addBeam = True

        # There are cases where duration < 1 need added beams
        # when the note is not already in a beam.  Such as
        # a plain 8th note with a slash.  This needs to be
        # converted into two 16th notes with a beam so that
        # *tremolo can reduce it back into a tremolo, since
        # it will only reduce beam groups.

        repeat: HumNum = duration
        repeat *= value
        repeat /= 4
        increment: HumNum = HumNum(4)
        increment /= value
        if repeat.denominator != 1:
            print(
                f'Error: tremolo repetition count must be an integer: {token}',
                file=sys.stderr)
            return
        tnotes = repeat.numerator

        self.storeFirstTremoloNoteInfo(token)

        beams: int = int(math.log(float(value), 2)) - 2
        markup: str = f'@{value.numerator}@'
        base: str = re.sub(markup, '', token.text)

        # complicated beamings are not allowed yet (no internal L/J markers in tremolo beam)
        hasBeamStart: bool = 'L' in base
        hasBeamStop: bool = 'J' in base

        if addBeam:
            hasBeamStart = True
            hasBeamStop = True

        # Currently not allowed to add tremolo to beamed notes, so remove all beaming:
        base = re.sub(r'[LJKk]+', '', base)
        startBeam: str = 'L' * beams
        endBeam: str = 'J' * beams

        # Set the rhythm of the tremolo notes.
        # Augmentation dot is expected adjacent to regular rhythm value.
        # Maybe allow anywhere?
        base = re.sub(r'\d+%?\d*\.*', str(value.numerator), base)
        initial: str = base
        if hasBeamStart:
            initial += startBeam
        terminal: str = base
        if hasBeamStop:
            terminal += endBeam

        # remove slur end from start of tremolo:
        terminal = re.sub(r'[(]+[<>]', '', terminal)

        token.text = initial
        token.ownerLine.createLineFromTokens()

        # Now fill in the rest of the tremolos.
        startTime: HumNum = token.durationFromStart
        timestamp: HumNum = startTime + increment
        currTok: HumdrumToken = token.nextToken(0)
        counter: int = 1

        while currTok is not None:
            if not currTok.isData:
                currTok = currTok.nextToken(0)
                continue

            duration: HumNum = currTok.ownerLine.duration
            if duration == 0:
                # grace note line, so skip
                currTok = currTok.nextToken(0)
                continue

            cstamp: HumNum = currTok.durationFromStart
            if cstamp < timestamp:
                currTok = currTok.nextToken(0)
                continue

            if cstamp > timestamp:
                print('\tWarning: terminating tremolo insertion early',
                      file=sys.stderr)
                print(f'\tCSTAMP : {cstamp} TSTAMP : {timestamp}',
                      file=sys.stderr)
                break

            counter += 1
            if counter == tnotes:
                currTok.text = terminal
                self.storeLastTremoloNoteInfo(currTok)
            else:
                currTok.text = base
            currTok.ownerLine.createLineFromTokens()
            if counter >= tnotes:
                # done with inserting of tremolo notes.
                break

            timestamp += increment
            currTok = currTok.nextToken(0)
    def __init__(
            self,
            line: str = '',
            asGlobalToken: bool = False,
            ownerFile=None  # HumdrumFile
    ) -> None:
        from converter21.humdrum import HumdrumFile
        super().__init__()  # initialize the HumHash fields

        '''
            _text: the line's text string
        '''
        if len(line) > 0 and line[-1] == '\n':
            # strip off any trailing LF
            line = line[:-1]

        self._text: str = line

        '''
        // owner: This is the HumdrumFile which manages the given line.
        '''
        self._ownerFile: HumdrumFile = ownerFile

        '''
        // m_lineindex: Used to store the index number of the HumdrumLine in
        // the owning HumdrumFile object.
        // This variable is filled by HumdrumFileStructure::analyzeLines().
        '''
        self._lineIndex: int = -1

        '''
        // m_tokens: Used to store the individual tab-separated token fields
        // on a line.  These are prepared automatically after reading in
        // a full line of text (which is accessed throught the string parent
        // class).  If the full line is changed, the tokens are not updated
        // automatically -- use createTokensFromLine().  Likewise the full
        // text line is not updated if any tokens are changed -- use
        // createLineFromTokens() in that case.  The second case is more
        // useful: you can read in a HumdrumFile, tweak the tokens, then
        // reconstruct the full line and print out again.
        // This variable is filled by HumdrumFile::read().
        // The contents of this vector should be deleted when deconstructing
        // a HumdrumLine object.
        '''
        self._tokens: t.List[HumdrumToken] = []
        if asGlobalToken:
            self._tokens = [HumdrumToken(line)]

        '''
        // m_tabs: Used to store a count of the number of tabs between
        // each token on a line.  This is the number of tabs after the
        // token at the given index (so no tabs before the first token).
        '''
        self._numTabsAfterToken: t.List[int] = []
        if asGlobalToken:
            self._numTabsAfterToken = [0]

        '''
        // m_duration: This is the "duration" of a line.  The duration is
        // equal to the minimum time unit of all durational tokens on the
        // line.  This also includes null tokens when the duration of a
        // previous note in a previous spine is ending on the line, so it is
        // not just the minimum duration on the line.
        // This variable is filled by HumdrumFileStructure::analyzeRhythm().
        '''
        self._duration: HumNum = -1.0

        '''
        // m_durationFromStart: This is the cumulative duration of all lines
        // prior to this one in the owning HumdrumFile object.  For example,
        // the first notes in a score start at time 0, If the duration of the
        // first data line is 1 quarter note, then the durationFromStart for
        // the second line will be 1 quarter note.
        // This variable is filled by HumdrumFileStructure::analyzeRhythm().
        '''
        self._durationFromStart: HumNum = -1.0

        '''
        // m_durationFromBarline: This is the cumulative duration from the
        // last barline to the current data line.
        // This variable is filled by HumdrumFileStructure::analyzeMeter().
        '''
        self._durationFromBarline: HumNum = -1.0

        '''
        // m_durationToBarline: This is the duration from the start of the
        // current line to the next barline in the owning HumdrumFile object.
        // This variable is filled by HumdrumFileStructure::analyzeMeter().
        '''
        self._durationToBarline: HumNum = -1.0

        '''
        // m_linkedParameters: List of Humdrum tokens which are parameters
        // (mostly only layout parameters at the moment)
        '''
        self._linkedParameters: t.List[HumdrumToken] = []

        '''
        // m_rhythm_analyzed: True if duration information from HumdrumFile
        // has been added to line.
        '''
        self._rhythmAnalyzed: bool = False

        '''
            We are also a HumHash, and that was initialized via super() above.
            But we want our default HumHash prefix to be '!!', not ''
        '''
        self.prefix: str = '!!'
 def insertToken(self, index: int, token: t.Union[HumdrumToken, str], tabCount: int = 0) -> None:
     if isinstance(token, str):
         token = HumdrumToken(token)
     self._tokens.insert(index, token)
     self._numTabsAfterToken.insert(index, tabCount)
 def appendToken(self, token: t.Union[HumdrumToken, str], tabCount: int = 0) -> None:
     if isinstance(token, str):
         token = HumdrumToken(token)
     self._tokens.append(token)
     self._numTabsAfterToken.append(tabCount)
Beispiel #28
0
    def expandFingerTremolo(self, token1: HumdrumToken, token2: HumdrumToken):
        if token2 is None:
            return

        m = re.search(r'@@(\d+)@@', token1.text)
        if not m:
            return

        value: int = int(m.group(1))
        if not Convert.isPowerOfTwo(HumNum(value)):
            print(f'Error: not a power of two: {token1}', file=sys.stderr)
            return
        if value < 8:
            print(
                f'Error: tremolo can only be eighth-notes or shorter: {token1}',
                file=sys.stderr)
            return

        duration: HumNum = Convert.recipToDuration(token1.text)
        count: HumNum = duration

        count *= value
        count /= 4
        if count.denominator != 1:
            print(
                f'Error: tremolo repetition count must be an integer: {token1}',
                file=sys.stderr)
            return
        increment: HumNum = HumNum(4)
        increment /= value

        tnotes: int = count.numerator * 2

        self.storeFirstTremoloNoteInfo(token1)

        beams: int = int(math.log(float(value), 2)) - 2
        markup: str = f'@@{value}@@'
        base1: str = token1.text
        base1 = re.sub(markup, '', base1)
        # Currently not allowed to add tremolo to beamed notes, so remove all beaming:
        base1 = re.sub(r'[LJKk]+', '', base1)
        startBeam: str = 'L' * beams
        endBeam: str = 'J' * beams

        # Set the rhythm of the tremolo notes.
        # Augmentation dot is expected adjacent to regular rhythm value.
        # Maybe allow anywhere?
        base1 = re.sub(r'\d+%?\d*\.*', str(value), base1)
        initial: str = base1 + startBeam
        # remove slur end from start of tremolo
        initial = re.sub(r'[)]+[<>]?', '', initial)

        # remove slur information from middle of tremolo
        base1 = re.sub(r'[()]+[<>]?', '', base1)

        token1.text = initial
        token1.ownerLine.createLineFromTokens()

        base2: str = token2.text
        base2 = re.sub(markup, '', base2)
        base2 = re.sub(r'[LJKk]+', '', base2)
        base2 = re.sub(r'\d+%?\d*\.*', str(value), base2)

        terminal: str = base2 + endBeam
        # remove slur start information from end of tremolo:
        terminal = re.sub(r'[(]+[<>]?', '', terminal)

        state: bool = False

        # Now fill in the rest of the tremolos.
        startTime: HumNum = token1.durationFromStart
        timestamp: HumNum = startTime + increment
        currTok: HumdrumToken = token1.nextToken(0)
        counter: int = 1
        while currTok is not None:
            if not currTok.isData:
                currTok = currTok.nextToken(0)
                continue

            cstamp: HumNum = currTok.durationFromStart
            if cstamp < timestamp:
                currTok = currTok.nextToken(0)
                continue

            if cstamp > timestamp:
                print('\tWarning: terminating tremolo insertion early',
                      file=sys.stderr)
                print(f'\tCSTAMP : {cstamp} TSTAMP : {timestamp}',
                      file=sys.stderr)
                break

            counter += 1
            if counter == tnotes:
                currTok.text = terminal
                self.storeLastTremoloNoteInfo(currTok)
            else:
                if state:
                    currTok.text = base1
                else:
                    currTok.text = base2
                state = not state

            currTok.ownerLine.createLineFromTokens()
            if counter >= tnotes:
                # done with inserting of tremolo notes
                break

            timestamp += increment
            currTok = currTok.nextToken(0)
Beispiel #29
0
    def _linkTieEndpoints(tieStart: HumdrumToken, startSubtokenIdx: int,
                          tieEnd: HumdrumToken, endSubtokenIdx: int) -> None:
        durTag: str = 'tieDuration'
        startTag: str = 'tieStart'
        endTag: str = 'tieEnd'
        startNumTag: str = 'tieStartSubtokenNumber'
        endNumTag: str = 'tieEndSubtokenNumber'

        startSubtokenNumber: int = startSubtokenIdx + 1
        endSubtokenNumber: int = endSubtokenIdx + 1

        if tieStart.isChord:
            if startSubtokenNumber > 0:
                startSuffix: str = str(startSubtokenNumber)
                durTag += startSuffix
                endNumTag += startSuffix
                endTag += startSuffix

        if tieEnd.isChord:
            if endSubtokenNumber > 0:
                endSuffix: str = str(endSubtokenNumber)
                startTag += endSuffix
                startNumTag += endSuffix

        tieStart.setValue('auto', endTag, tieEnd)
        tieStart.setValue('auto', 'id', tieStart)
        if endSubtokenNumber > 0:
            tieStart.setValue('auto', endNumTag, str(endSubtokenNumber))

        tieEnd.setValue('auto', startTag, tieStart)
        tieEnd.setValue('auto', 'id', tieEnd)
        if startSubtokenNumber > 0:
            tieEnd.setValue('auto', startNumTag, str(startSubtokenNumber))

        duration: HumNum = opFrac(tieEnd.durationFromStart -
                                  tieStart.durationFromStart)
        tieStart.setValue('auto', durTag, duration)
Beispiel #30
0
    def transferTokens(self, outFile: HumdrumFile, recip: bool):
        line: HumdrumLine = HumdrumLine()
        voice: GridVoice = None
        emptyStr: str = '.'

        if self.isMeasureSlice:
            if len(self.parts) > 0:
                if len(self.parts[0].staves[0].voices) > 0:
                    voice = self.parts[0].staves[0].voices[0]
                    if voice.token is not None:
                        emptyStr = voice.token.text
                    else:
                        emptyStr = '=YYYYYY'
                else:
                    emptyStr = '=YYYYYY'
        elif self.isInterpretationSlice:
            emptyStr = '*'
        elif self.isLocalLayoutSlice:
            emptyStr = '!'
        elif not self.hasSpines:
            emptyStr = '???'

        if recip:
            token: HumdrumToken = None

            if self.isNoteSlice:
                token = self._createRecipTokenFromDuration(self.duration)
            elif self.isClefSlice:
                token = HumdrumToken('*')
                emptyStr = '*'
            elif self.isMeasureSlice:
                if len(self.parts[0].staves[0]) > 0:
                    voice = self.parts[0].staves[0].voices[0]
                    token = HumdrumToken(voice.token.text)
                else:
                    token = HumdrumToken('=XXXXX')
                emptyStr = token.text
            elif self.isInterpretationSlice:
                token = HumdrumToken('*')
                emptyStr = '*'
            elif self.isGraceSlice:
                token = HumdrumToken('q')
                emptyStr = '.'
            elif self.hasSpines:
                token = HumdrumToken('55')
                emptyStr = '!'

            if token is not None:
                if self.hasSpines:
                    line.appendToken(token)
                else:
                    token = None

        # extract the Tokens from each part/staff
        for p in range(len(self.parts) - 1, -1, -1):
            part = self.parts[p]
            if not self.hasSpines and p != 0:
                continue
            for s in range(len(part.staves) - 1, -1, -1):
                staff = part.staves[s]
                if not self.hasSpines and s != 0:
                    continue
                if len(staff.voices) == 0:
                    # 888: fix this later.  For now if there are no notes
                    # 888: ... on the staff, add a null token.  Fix so that
                    # 888: ... all open voices are given null tokens.
                    line.appendToken(HumdrumToken(emptyStr))
                else:
                    for voice in staff.voices:  # NOT reversed (voices different from parts/staves)
                        if voice is not None and voice.token is not None:
                            line.appendToken(voice.token)
                        else:
                            line.appendToken(HumdrumToken(emptyStr))

                if not self.hasSpines:
                    # Don't add sides to non-spined lines
                    continue

                maxxcount: int = self.getXmlIdCount(p, s)
                maxdcount: int = self.getDynamicsCount(p, s)
                maxvcount: int = self.getVerseCount(p, s)
                self.transferSidesFromStaff(line, staff, emptyStr, maxxcount,
                                            maxdcount, maxvcount)

            if not self.hasSpines:
                # Don't add sides to non-spined lines
                continue

            maxhcount: int = self.getHarmonyCount(p)
            maxfcount: int = self.getFiguredBassCount(p)
            self.transferSidesFromPart(line, part, emptyStr, maxhcount,
                                       maxfcount)

        outFile.appendLine(line)