Ejemplo n.º 1
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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
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
Ejemplo n.º 4
0
    def m21VersionIsAtLeast(
            neededVersion: t.Tuple[int, int, int, str]) -> bool:
        # m21.VERSION[0] * 10000 + m21.VERSION[1] * 100 + m21.VERSION[2]
        if len(m21.VERSION) == 0:
            raise HumdrumInternalError('music21 version must be set!')

        # compare element 0
        if m21.VERSION[0] < neededVersion[0]:
            return False
        if m21.VERSION[0] > neededVersion[0]:
            return True

        # element 0 is equal... go on to next element
        if len(m21.VERSION) == 1 or len(neededVersion) == 1:
            # there is no next element to compare, so we are done.
            # result is True only if m21 version has >= elements of needed version.
            # if neededVersion has more elements, then result is False
            return len(m21.VERSION) >= len(neededVersion)

        # compare element 1
        if m21.VERSION[1] < neededVersion[1]:
            return False
        if m21.VERSION[1] > neededVersion[1]:
            return True

        # element 1 is equal... go on to next element
        if len(m21.VERSION) == 2 or len(neededVersion) == 2:
            # there is no next element to compare, so we are done.
            # result is True only if m21 version has >= elements of needed version.
            # if neededVersion has more elements, then result is False
            return len(m21.VERSION) >= len(neededVersion)

        # compare element 2
        if m21.VERSION[2] < neededVersion[2]:
            return False
        if m21.VERSION[2] > neededVersion[2]:
            return True

        # element 2 is equal... go on to next element
        if len(m21.VERSION) == 3 or len(neededVersion) == 3:
            # there is no next element to compare, so we are done.
            # result is True only if m21 version has >= elements of needed version.
            # if neededVersion has more elements, then result is False
            return len(m21.VERSION) >= len(neededVersion)

        # compare element 3 (probably a string)
        if m21.VERSION[3] < neededVersion[3]:
            return False
        if m21.VERSION[3] > neededVersion[3]:
            return True

        return True  # four elements equal, that's all we care about
Ejemplo n.º 5
0
    def setTokenLayer(self, layerIndex: int, token: HumdrumToken,
                      duration: HumNum) -> GridVoice:
        if layerIndex < 0:
            raise HumdrumInternalError(
                f'Error: layer index is {layerIndex} for {token}')

        if layerIndex > len(self.voices) - 1:
            for _ in range(len(self.voices),
                           layerIndex + 1):  # range includes layerIndex
                self.voices.append(None)

        gv: GridVoice = GridVoice(token, duration)
        self.voices[layerIndex] = gv
        return gv
Ejemplo n.º 6
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
Ejemplo n.º 7
0
    def analyzeTextRepetition(self) -> None:
        spineStarts: t.List[t.Optional[HumdrumToken]] = self.spineStartList

        for start in spineStarts:
            ijstate: bool = False
            startij: bool = False
            lastIJToken: t.Optional[
                HumdrumToken] = None  # last token seen in ij range

            if start is None:
                raise HumdrumInternalError(
                    'start that is None found in spineStarts')

            # BUGFIX: **sylb -> **silbe
            if not start.isDataType('**text') and not start.isDataType(
                    '**silbe'):
                continue

            current: t.Optional[HumdrumToken] = start
            while current is not None:
                if current.isNull:
                    current = current.nextToken0
                    continue

                if current.isInterpretation:
                    if current.text == '*ij':
                        startij = True
                        ijstate = True
                    elif current.text == '*Xij':
                        startij = False
                        ijstate = False
                        if lastIJToken is not None:
                            lastIJToken.setValue('auto', 'ij-end', 'true')
                            lastIJToken = None
                    current = current.nextToken0
                    continue

                if current.isData:
                    if ijstate:
                        current.setValue('auto', 'ij', 'true')
                        if startij:
                            current.setValue('auto', 'ij-begin', 'true')
                            startij = False
                        lastIJToken = current

                current = current.nextToken0
Ejemplo n.º 8
0
    def resolveNullTokens(self) -> None:
        if self._analyses.nullsAnalyzed:
            return

        self._analyses.nullsAnalyzed = True
        if not self.areStrandsAnalyzed:
            self.analyzeStrands()

        data: t.Optional[HumdrumToken] = None
        strandPair: TokenPair
        for strandPair in self._strand1d:
            token: t.Optional[HumdrumToken] = strandPair.first
            strandEnd: t.Optional[HumdrumToken] = strandPair.last
            if t.TYPE_CHECKING:
                # after analyzeStrands, no pair in self._strand1d will have Nones in it.
                assert token is not None
                assert strandEnd is not None

            while token != strandEnd:
                if token is None:
                    # we never reached strandEnd, but we're done
                    raise HumdrumInternalError(
                        f'never found strandEnd ({strandEnd})')

                if not token.isData:
                    token = token.nextToken0
                    continue

                if data is None:
                    data = token
                    token.nullResolution = data
                    token = token.nextToken0
                    continue

                if token.isNull:
                    token.nullResolution = data
                else:
                    data = token

                token = token.nextToken0
Ejemplo n.º 9
0
    def base40ToKern(b40: int) -> str:
        octave: int = b40 // 40
        accidental: int = Convert.base40ToAccidental(b40)
        diatonic: int = Convert.base40ToDiatonic(b40) % 7
        base: str = 'a'
        if diatonic == 0:
            base = 'c'
        elif diatonic == 1:
            base = 'd'
        elif diatonic == 2:
            base = 'e'
        elif diatonic == 3:
            base = 'f'
        elif diatonic == 4:
            base = 'g'
        elif diatonic == 5:
            base = 'a'
        elif diatonic == 6:
            base = 'b'

        if octave < 4:
            base = base.upper()

        repeat: int = 0
        if octave > 4:
            repeat = octave - 4
        elif octave < 3:
            repeat = 3 - octave

        if repeat > 12:
            raise HumdrumInternalError(
                f'Error: unreasonable octave value: {octave} for {b40}')

        output: str = base * (1 + repeat)
        if accidental > 0:
            output += '#' * accidental
        elif accidental < 0:
            output += '-' * -accidental

        return output
Ejemplo n.º 10
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] = []
Ejemplo n.º 11
0
    def setOrigin(self, *ns1ns2keyvalue):  # origin: HumdrumToken
        from converter21.humdrum import HumdrumToken
        origin = ns1ns2keyvalue[-1]
        ns1ns2key = ns1ns2keyvalue[:-1]
        ns1, ns2, key = fixupNamespace1Namespace2Key(*ns1ns2key)

        if not isinstance(origin, HumdrumToken):
            raise HumdrumInternalError(
                'invalid origin token in HumHash.setOrigin')

        if self._parameters is None:
            return

        if ns1 not in self._parameters:
            return

        if ns2 not in self._parameters[ns1]:
            return

        if key not in self._parameters[ns1][ns2]:
            return

        self._parameters[ns1][ns2][key].origin = origin
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
    def __init__(self,
                 ownerMeasure,
                 timestamp: HumNumIn,
                 sliceType: SliceType,
                 partCount: int = 0,
                 fromSlice: t.Optional['GridSlice'] = None) -> None:
        from converter21.humdrum import GridMeasure
        from converter21.humdrum import HumGrid
        self._timestamp: HumNum = opFrac(timestamp)
        self._type: SliceType = sliceType
        if not isinstance(ownerMeasure, GridMeasure):
            raise HumdrumInternalError('GridSlice init: invalid ownerMeasure')
        self._measure: GridMeasure = ownerMeasure  # enclosing measure
        self._ownerGrid: HumGrid = self._measure.ownerGrid  # measure's enclosing grid

        self.parts: t.List[GridPart] = []
        if fromSlice is None:
            # GridSlice::GridSlice -- Constructor.  If partcount is positive, then
            #    allocate the desired number of parts (still have to allocate staves
            #    in part before using).
            for _ in range(0, partCount):
                part: GridPart = GridPart()
                staff: GridStaff = GridStaff()
                voice: GridVoice = GridVoice()
                self.parts.append(part)
                part.staves.append(staff)
                staff.voices.append(voice)
        else:
            # This constructor allocates the matching part and staff count of the
            # input fromSlice parameter.  There will be no GridVoices allocated inside
            # the GridStaffs (they will be required to have at least one).
            for fromPart in fromSlice.parts:
                part = GridPart()
                self.parts.append(part)
                for _ in fromPart.staves:
                    staff = GridStaff()
                    part.staves.append(staff)
Ejemplo n.º 14
0
    def addGraceToken(self, tok: str, timestamp: HumNum, part: int, staff: int,
                      voice: int, maxStaff: int,
                      graceNumber: int) -> GridSlice:
        if graceNumber < 1:
            raise HumdrumInternalError(
                'ERROR: graceNumber {} has to be larger than 0')

        gs: GridSlice = None
        if not self.slices:
            # add a new GridSlice to an empty list.
            gs = GridSlice(self, timestamp, SliceType.GraceNotes, maxStaff)
            gs.addToken(tok, part, staff, voice)
            self.slices.append(gs)
            return gs

        if timestamp > self.slices[-1].timestamp:
            # Grace note needs to be added at the end of a measure.
            idx: int = len(self.slices) - 1  # pointing at last slice
            counter: int = 0
            while idx >= 0:
                if self.slices[idx].isGraceSlice:
                    counter += 1
                    if counter == graceNumber:
                        # insert grace note into this slice
                        self.slices[idx].addToken(tok, part, staff, voice)
                        return self.slices[idx]
                elif self.slices[idx].isLocalLayoutSlice:
                    # skip over any layout parameter lines
                    idx -= 1
                    continue

                if self.slices[idx].isDataSlice:
                    # insert grace note after this note
                    gs = GridSlice(self, timestamp, SliceType.GraceNotes,
                                   maxStaff)
                    gs.addToken(tok, part, staff, voice)
                    self.slices.insert(idx + 1, gs)
                    return gs

                idx -= 1

            return None  # couldn't find anywhere to insert

        # search for existing line with same timestamp on a data slice:
        foundIndex: int = -1
        for idx, gridSlice in enumerate(self.slices):
            if timestamp < gridSlice.timestamp:
                raise HumdrumInternalError(
                    f'''STRANGE CASE 2 IN GRIDMEASURE::ADDGRACETOKEN
\tGRACE TIMESTAMP: {timestamp}
\tTEST  TIMESTAMP: {gridSlice.timestamp}''')

            if gridSlice.isDataSlice:
                if gridSlice.timestamp == timestamp:
                    foundIndex = idx
                    break

        idx: int = foundIndex - 1
        counter: int = 0
        while idx >= 0:
            if self.slices[idx].isGraceSlice:
                counter += 1
                if counter == graceNumber:
                    # insert grace note into this slice
                    self.slices[idx].addToken(tok, part, staff, voice)
                    return self.slices[idx]
            elif self.slices[idx].isLocalLayoutSlice:
                # skip over any layout parameter lines
                idx -= 1
                continue

            if self.slices[idx].isDataSlice:
                # insert grace note after this note
                gs = GridSlice(self, timestamp, SliceType.GraceNotes, maxStaff)
                gs.addToken(tok, part, staff, voice)
                self.slices.insert(idx + 1, gs)
                return gs

            idx -= 1

        # grace note should be added at start of measure
        gs = GridSlice(self, timestamp, SliceType.GraceNotes, maxStaff)
        gs.addToken(tok, part, staff, voice)
        self.slices.insert(0, gs)
        return gs
Ejemplo n.º 15
0
 def ownerGrid(self, newOwnerGrid) -> None:  # newOwnerGrid: HumGrid
     from converter21.humdrum import HumGrid
     if not isinstance(newOwnerGrid, HumGrid):
         raise HumdrumInternalError('invalid newOwnerGrid')
     self._ownerGrid = newOwnerGrid
Ejemplo n.º 16
0
    def __init__(self, score: m21.stream.Score, ownerWriter) -> None:
        from converter21.humdrum import HumdrumWriter
        self.ownerWriter: HumdrumWriter = ownerWriter

        if not isinstance(score, m21.stream.Score):
            raise HumdrumInternalError('ScoreData must be initialized with a music21 Score object')

        self.m21Score: m21.stream.Score = score
        self.spannerBundle: m21.spanner.SpannerBundle = ownerWriter.spannerBundle

        self.parts: t.List[PartData] = []

        # key is id(m21Object): a large integer that is actually the mem address of m21Object
        self.eventFromM21Object: t.Dict[int, EventData] = {}

        # Following staff group code stolen from musicxml exporter in music21.
        # Keep it up-to-date!

        staffGroups = self.m21Score.getElementsByClass('StaffGroup')
        joinableGroups: t.List[m21.layout.StaffGroup] = []

        # Joinable groups must consist of only PartStaffs with Measures
        # that exist in self.m21Score
        for sg in staffGroups:
            if len(sg) <= 1:
                continue
            if not all('PartStaff' in p.classes for p in sg):
                continue
            if not all(p.getElementsByClass('Measure') for p in sg):
                continue
            if not all(p in self.m21Score.parts for p in sg):
                continue
            joinableGroups.append(sg)

        # Deduplicate joinable groups (ex: bracket and brace enclose same PartStaffs)
        permutations = set()
        deduplicatedGroups: t.List[m21.layout.StaffGroup] = []
        for jg in joinableGroups:
            containedParts = tuple(jg)
            if containedParts not in permutations:
                deduplicatedGroups.append(jg)
            permutations.add(containedParts)
        joinableGroups = deduplicatedGroups

        partsWithMoreThanOneStaff: t.List[t.List[m21.stream.Part]] = []
        groupedParts: t.List[m21.stream.PartStaff] = []
        for jg in joinableGroups:
            partsWithMoreThanOneStaff.append([])
            for partStaff in jg:
                partsWithMoreThanOneStaff[-1].append(partStaff)
                groupedParts.append(partStaff)

        scorePartsStillToProcess = list(score.parts)
        for part in score.parts:  # includes PartStaffs, too
            if part not in scorePartsStillToProcess:
                # we already processed this due to a staff group
                continue

            if 'PartStaff' in part.classes and part in groupedParts:
                # make a new partData entry for these PartStaffs and fill it
                for partStaffList in partsWithMoreThanOneStaff:
                    if part in partStaffList:
                        partOfStavesData: PartData = PartData(partStaffList, self, len(self.parts))
                        self.parts.append(partOfStavesData)
                        for ps in partStaffList:
                            scorePartsStillToProcess.remove(ps)  # so we don't double process
                        break
            else:
                # make a new partData entry for the Part (one staff which is the part)
                partData: PartData = PartData([part], self, len(self.parts))
                self.parts.append(partData)
                scorePartsStillToProcess.remove(part)