From f1ab28c21144659c7be299aaddc088ae408fcf19 Mon Sep 17 00:00:00 2001 From: TimFelix <35711942+TimFelixBeyer@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:49:21 +0100 Subject: [PATCH] Small simplifications and speed-ups --- music21/abcFormat/__init__.py | 2 +- music21/braille/segment.py | 2 +- music21/chord/__init__.py | 10 +- music21/duration.py | 8 +- music21/humdrum/spineParser.py | 141 +++++++++++++-------------- music21/interval.py | 14 ++- music21/metadata/__init__.py | 10 +- music21/musicxml/m21ToXml.py | 20 ++-- music21/romanText/clercqTemperley.py | 4 +- music21/scale/__init__.py | 22 ++--- music21/tree/verticality.py | 4 +- 11 files changed, 111 insertions(+), 126 deletions(-) diff --git a/music21/abcFormat/__init__.py b/music21/abcFormat/__init__.py index b026887c2..91477a101 100644 --- a/music21/abcFormat/__init__.py +++ b/music21/abcFormat/__init__.py @@ -719,7 +719,7 @@ def getMetronomeMarkObject(self) -> tempo.MetronomeMark|None: # there may be more than one dur divided by a space referent = 0.0 # in quarter lengths for dur in durs.split(' '): - if dur.count('/') > 0: + if '/' in dur: n, d = dur.split('/') else: # this is an error case environLocal.printDebug(['incorrectly encoded / unparsable duration:', dur]) diff --git a/music21/braille/segment.py b/music21/braille/segment.py index 052dcf256..122d25a49 100644 --- a/music21/braille/segment.py +++ b/music21/braille/segment.py @@ -2060,7 +2060,7 @@ def extractBrailleElements( except BrailleSegmentException as notSupportedException: # pragma: no cover isExempt = [isinstance(music21Object, music21Class) for music21Class in excludeFromBrailleElements] - if isExempt.count(True) == 0: + if not any(isExempt): environRules.warn(f'{notSupportedException}') allElements.sort(key=lambda x: (x.offset, x.classSortOrder)) diff --git a/music21/chord/__init__.py b/music21/chord/__init__.py index db050b439..fd7364581 100644 --- a/music21/chord/__init__.py +++ b/music21/chord/__init__.py @@ -834,12 +834,12 @@ def __getitem__(self, key: int|str|note.Note|pitch.Pitch): keyErrorStr = f'Cannot access component with: {key!r}' if isinstance(key, str): - if key.count('.'): + if '.' in key: key, attrStr = key.split('.', 1) - if not attrStr.count('.'): - attributes = (attrStr,) - else: + if '.' in attrStr: attributes = tuple(attrStr.split('.')) + else: + attributes = (attrStr,) else: attributes = () @@ -931,7 +931,7 @@ def __setitem__(self, key, value): Traceback (most recent call last): ValueError: Chord index must be set to a valid note object ''' - if isinstance(key, str) and key.count('.'): + if isinstance(key, str) and '.' in key: keySplit = key.split('.') keyFind = '.'.join(keySplit[0:-1]) attr = keySplit[-1] diff --git a/music21/duration.py b/music21/duration.py index fe32f4a64..225262abf 100644 --- a/music21/duration.py +++ b/music21/duration.py @@ -385,7 +385,7 @@ def dottedMatch(qLen: OffsetQLIn, durType, match = quarterLengthToClosestType(preDottedLength) except DurationException: continue - if match is True: + if match: return (dots, durType) return (False, False) @@ -441,8 +441,8 @@ def quarterLengthToNonPowerOf2Tuplet( def quarterLengthToTuplet( qLen: OffsetQLIn, - maxToReturn=4, - tupletNumerators=defaultTupletNumerators + maxToReturn: int = 4, + tupletNumerators: list[int] = defaultTupletNumerators ) -> list[Tuplet]: ''' Returns a list of possible Tuplet objects for a @@ -738,7 +738,7 @@ def quarterConversion(qLen: OffsetQLIn) -> QuarterLengthConversion: def convertTypeToQuarterLength( dType: str, - dots=0, + dots: int = 0, tuplets: list[Tuplet]|None = None, dotGroups=None ) -> OffsetQL: diff --git a/music21/humdrum/spineParser.py b/music21/humdrum/spineParser.py index ca33c5122..d976d6d5e 100644 --- a/music21/humdrum/spineParser.py +++ b/music21/humdrum/spineParser.py @@ -1328,7 +1328,7 @@ def parse(self): thisObject = SpineComment(eventC) if thisObject.comment == '': thisObject = None - elif eventC.count(' '): + elif ' ' in eventC: thisObject = self.processChordEvent(eventC) else: # Note or Rest thisObject = self.processNoteEvent(eventC) @@ -2209,7 +2209,7 @@ def hdStringToNote(contents): # Detect rests first, because rests can contain manual positioning information, # which is also detected by the `matchedNote` variable above. - if contents.count('r'): + if 'r' in contents: thisObject = note.Rest() elif matchedNote: @@ -2232,91 +2232,88 @@ def hdStringToNote(contents): thisObject.pitch.accidental = matchedSharp.group(0) elif matchedFlat: thisObject.pitch.accidental = matchedFlat.group(0) - elif contents.count('n'): + elif 'n' in contents: thisObject.pitch.accidental = 'n' # 3.2.2 -- Slurs, Ties, Phrases # TODO: add music21 phrase information - if contents.count('{'): - for i in range(contents.count('{')): - pass # phraseMark start - if contents.count('}'): - for i in range(contents.count('}')): - pass # phraseMark end - if contents.count('('): - for i in range(contents.count('(')): - pass # slur start - if contents.count(')'): - for i in range(contents.count(')')): - pass # slur end - if contents.count('['): + for i in range(contents.count('{')): + pass # phraseMark start + for i in range(contents.count('}')): + pass # phraseMark end + for i in range(contents.count('(')): + pass # slur start + for i in range(contents.count(')')): + pass # slur end + if '[' in contents: thisObject.tie = tie.Tie('start') - elif contents.count(']'): + elif ']' in contents: thisObject.tie = tie.Tie('stop') - elif contents.count('_'): + elif '_' in contents: thisObject.tie = tie.Tie('continue') # 3.2.3 Ornaments - if contents.count('t'): + if 't' in contents: thisObject.expressions.append(expressions.HalfStepTrill()) - elif contents.count('T'): + elif 'T' in contents: thisObject.expressions.append(expressions.WholeStepTrill()) - if contents.count('w'): + if 'w' in contents: thisObject.expressions.append(expressions.HalfStepInvertedMordent()) - elif contents.count('W'): + elif 'W' in contents: thisObject.expressions.append(expressions.WholeStepInvertedMordent()) - elif contents.count('m'): + elif 'm' in contents: thisObject.expressions.append(expressions.HalfStepMordent()) - elif contents.count('M'): + elif 'M' in contents: thisObject.expressions.append(expressions.WholeStepMordent()) - if contents.count('S'): + if 'S' in contents: thisObject.expressions.append(expressions.Turn()) - elif contents.count('$'): + elif '$' in contents: thisObject.expressions.append(expressions.InvertedTurn()) - elif contents.count('R'): + elif 'R' in contents: t1 = expressions.Turn() t1.connectedToPrevious = True # true by default, but explicitly thisObject.expressions.append(t1) - if contents.count(':'): + if ':' in contents: # TODO: deal with arpeggiation -- should have been in a # chord structure pass - if contents.count('O'): + if 'O' in contents: thisObject.expressions.append(expressions.Ornament()) # generic ornament # 3.2.4 Articulation Marks - if contents.count("'"): + if "'" in contents: thisObject.articulations.append(articulations.Staccato()) - if contents.count('"'): + if '"' in contents: thisObject.articulations.append(articulations.Pizzicato()) - if contents.count('`'): + if '`' in contents: # called 'attacca' mark but means staccatissimo: # http://www.music-cog.ohio-state.edu/Humdrum/representations/kern.rep.html thisObject.articulations.append(articulations.Staccatissimo()) - if contents.count('~'): + if '~' in contents: thisObject.articulations.append(articulations.Tenuto()) - if contents.count('^'): + if '^' in contents: thisObject.articulations.append(articulations.Accent()) - if contents.count(';'): + if ';' in contents: thisObject.expressions.append(expressions.Fermata()) # 3.2.5 Up & Down Bows - if contents.count('v'): + if 'v' in contents: thisObject.articulations.append(articulations.UpBow()) - elif contents.count('u'): + elif 'u' in contents: thisObject.articulations.append(articulations.DownBow()) # 3.2.6 Stem Directions - if contents.count('/'): + if '/' in contents: thisObject.stemDirection = 'up' - elif contents.count('\\'): + elif '\\' in contents: thisObject.stemDirection = 'down' + # 3.2.7 Duration + # 3.2.8 N-Tuplets @@ -2327,7 +2324,7 @@ def hdStringToNote(contents): durationFirst = int(foundRational.group(1)) durationSecond = float(foundRational.group(2)) thisObject.duration.quarterLength = 4 * durationSecond / durationFirst - if contents.count('.'): + if '.' in contents: thisObject.duration.dots = contents.count('.') elif foundNumber: @@ -2337,20 +2334,16 @@ def hdStringToNote(contents): if durationString == '000': # for larger values, see https://extras.humdrum.org/man/rscale/ thisObject.duration.type = 'maxima' - if contents.count('.'): - thisObject.duration.dots = contents.count('.') elif durationString == '00': # for larger values, see https://extras.humdrum.org/man/rscale/ thisObject.duration.type = 'longa' - if contents.count('.'): - thisObject.duration.dots = contents.count('.') else: thisObject.duration.type = 'breve' - if contents.count('.'): - thisObject.duration.dots = contents.count('.') + if '.' in contents: + thisObject.duration.dots = contents.count('.') elif durationType in duration.typeFromNumDict: thisObject.duration.type = duration.typeFromNumDict[durationType] - if contents.count('.'): + if '.' in contents: thisObject.duration.dots = contents.count('.') else: dT = int(durationType) + 0.0 @@ -2369,26 +2362,26 @@ def hdStringToNote(contents): # humdrum tuplets that breaks normal usage. TODO: Refactor adding a Flavor = 'JRP' # code that uses this other method... JRP = flavors['JRP'] - if JRP is False and contents.count('.'): + if JRP is False and '.' in contents: newTup.durationNormal = duration.durationTupleFromTypeDots( newTup.durationNormal.type, contents.count('.')) thisObject.duration.appendTuplet(newTup) - if JRP is True and contents.count('.'): + if JRP is True and '.' in contents: thisObject.duration.dots = contents.count('.') # call Duration.TupletFixer after to correct this. - # 3.2.9 Grace Notes and Groupettos - if contents.count('q'): + # 3.2.9 Grace Notes and Groupettos + if 'q' in contents: thisObject = thisObject.getGrace() thisObject.duration.type = 'eighth' - elif contents.count('Q'): + elif 'Q' in contents: thisObject = thisObject.getGrace() thisObject.duration.slash = False thisObject.duration.type = 'eighth' - elif contents.count('P'): + elif 'P' in contents: thisObject = thisObject.getGrace(appoggiatura=True) - elif contents.count('p'): + elif 'p' in contents: pass # end appoggiatura duration -- not needed in music21... # 3.2.10 Beaming @@ -2428,53 +2421,53 @@ def hdStringToMeasure(contents, previousMeasure=None): barline = bar.Barline() - if contents.count('-'): + if '-' in contents: barline.type = 'none' - elif contents.count("'"): + elif "'" in contents: barline.type = 'short' - elif contents.count('`'): + elif '`' in contents: barline.type = 'tick' - elif contents.count('||'): + elif '||' in contents: barline.type = 'double' if contents.count(':') > 1: barline.repeatDots = 'both' - elif contents.count(':|'): + elif ':|' in contents: barline.repeatDots = 'left' - elif contents.count('|:'): + elif '|:' in contents: barline.repeatDots = 'right' - elif contents.count('!!'): + elif '!!' in contents: barline.type = 'heavy-heavy' if contents.count(':') > 1: barline.repeatDots = 'both' - elif contents.count(':!'): + elif ':!' in contents: barline.repeatDots = 'left' - elif contents.count('!:'): + elif '!:' in contents: barline.repeatDots = 'right' - elif contents.count('|!'): + elif '|!' in contents: barline.type = 'final' if contents.count(':') > 1: barline.repeatDots = 'both' - elif contents.count(':|'): + elif ':|' in contents: barline.repeatDots = 'left' - elif contents.count('!:'): + elif '!:' in contents: barline.repeatDots = 'right' - elif contents.count('!|'): + elif '!|' in contents: barline.type = 'heavy-light' if contents.count(':') > 1: barline.repeatDots = 'both' - elif contents.count(':!'): + elif ':!' in contents: barline.repeatDots = 'left' - elif contents.count('|:'): + elif '|:' in contents: barline.repeatDots = 'right' - elif contents.count('|'): + elif '|' in contents: barline.type = 'regular' if contents.count(':') > 1: barline.repeatDots = 'both' - elif contents.count(':|'): + elif ':|' in contents: barline.repeatDots = 'left' - elif contents.count('|:'): + elif '|:' in contents: barline.repeatDots = 'right' - elif contents.count('=='): + elif '==' in contents: barline.type = 'double' if contents.count(':') > 1: barline.repeatDots = 'both' @@ -2484,7 +2477,7 @@ def hdStringToMeasure(contents, previousMeasure=None): 'Cannot import a double bar visually rendered as a single bar -- ' + 'not sure exactly what that would mean anyhow.') - if contents.count(';'): + if ';' in contents: barline.pause = expressions.Fermata() if previousMeasure is not None: diff --git a/music21/interval.py b/music21/interval.py index abcd2f381..38c65c54b 100644 --- a/music21/interval.py +++ b/music21/interval.py @@ -1060,11 +1060,9 @@ def _simpleStepsAndOctaves(self) -> tuple[int, int]: Returns simpleUndirectedSteps and undirectedOctaves. ''' # unisons (even augmented) are neither steps nor skips. - steps, octaves = math.modf(self.undirected / 7) - steps = int(steps * 7 + 0.001) - octaves = int(octaves) + octaves, steps = divmod(self.undirected, 7) if steps == 0: - octaves = octaves - 1 + octaves -= 1 steps = 7 return steps, octaves @@ -1417,7 +1415,7 @@ def transposePitch(self, p: pitch.Pitch, *, inPlace=False): newPitch = copy.deepcopy(p) newPitch.diatonicNoteNum = pitchDNN + self.staffDistance - if useImplicitOctave is True: + if useImplicitOctave: newPitch.octave = None if not inPlace: @@ -1508,7 +1506,7 @@ def transposePitchKeyAware( offsetFromKey = pAlter - stepAlter newPitch = self.transposePitch(p, inPlace=inPlace) - if inPlace is True: + if inPlace: newPitch = p newAccidentalByStep = k.accidentalByStep(newPitch.step) @@ -1520,7 +1518,7 @@ def transposePitchKeyAware( elif newPitch.accidental is not None: newPitch.accidental = None - if inPlace is False: + if not inPlace: return newPitch def getDiatonic(self, specifier: Specifier|str) -> DiatonicInterval: @@ -3526,7 +3524,7 @@ def _diatonicTransposePitch(self, and oldPitch2Accidental.name == 'natural'): pitch2.accidental = oldPitch2Accidental - if useImplicitOctave is True: + if useImplicitOctave: pitch2.octave = None if not inPlace: diff --git a/music21/metadata/__init__.py b/music21/metadata/__init__.py index ecdd633bf..640546656 100755 --- a/music21/metadata/__init__.py +++ b/music21/metadata/__init__.py @@ -2045,7 +2045,7 @@ def _isContributorUniqueName(uniqueName: str) -> bool: False ''' prop: PropertyDescription|None = ( - properties.UNIQUE_NAME_TO_PROPERTY_DESCRIPTION.get(uniqueName, None) + properties.UNIQUE_NAME_TO_PROPERTY_DESCRIPTION.get(uniqueName) ) if prop is None: return False @@ -2095,7 +2095,7 @@ def _isContributorNamespaceName(namespaceName: str) -> bool: False ''' prop: PropertyDescription|None = ( - properties.NAMESPACE_NAME_TO_PROPERTY_DESCRIPTION.get(namespaceName, None) + properties.NAMESPACE_NAME_TO_PROPERTY_DESCRIPTION.get(namespaceName) ) if prop is None: return False @@ -2133,7 +2133,7 @@ def _namespaceNameNeedsArticleNormalization(namespaceName: str) -> bool: False ''' prop: PropertyDescription|None = ( - properties.NAMESPACE_NAME_TO_PROPERTY_DESCRIPTION.get(namespaceName, None) + properties.NAMESPACE_NAME_TO_PROPERTY_DESCRIPTION.get(namespaceName) ) if prop is None: return False @@ -2173,7 +2173,7 @@ def _contributorRoleToUniqueName(role: str|None) -> str: return 'otherContributor' prop: PropertyDescription|None = ( - properties.UNIQUE_NAME_TO_PROPERTY_DESCRIPTION.get(role, None) + properties.UNIQUE_NAME_TO_PROPERTY_DESCRIPTION.get(role) ) if prop is None: @@ -2207,7 +2207,7 @@ def _get(self, name: str, isCustom: bool) -> tuple[ValueType, ...]: ' Call addCustom/setCustom/getCustom for custom names.') name = uniqueName - valueList: list[ValueType]|None = self._contents.get(name, None) + valueList: list[ValueType]|None = self._contents.get(name) if not valueList: # return empty tuple diff --git a/music21/musicxml/m21ToXml.py b/music21/musicxml/m21ToXml.py index d6321e801..9e7da2aa8 100644 --- a/music21/musicxml/m21ToXml.py +++ b/music21/musicxml/m21ToXml.py @@ -4499,7 +4499,7 @@ def pitchToXml(self, p: pitch.Pitch): ''' mxPitch = Element('pitch') - _setTagTextFromAttribute(p, mxPitch, 'step') + _setTagTextFromAttribute(p, mxPitch, 'step', 'step') if p.accidental is not None: mxAlter = SubElement(mxPitch, 'alter') mxAlter.text = str(common.numToIntOrFloat(p.accidental.alter)) @@ -4580,11 +4580,11 @@ def fretNoteToXml(self, fretNote) -> Element: ''' mxFrameNote = Element('frame-note') - _setTagTextFromAttribute(fretNote, mxFrameNote, 'string') - _setTagTextFromAttribute(fretNote, mxFrameNote, 'fret') + _setTagTextFromAttribute(fretNote, mxFrameNote, 'string', 'string') + _setTagTextFromAttribute(fretNote, mxFrameNote, 'fret', 'fret') if fretNote.fingering is not None: - _setTagTextFromAttribute(fretNote, mxFrameNote, 'fingering') + _setTagTextFromAttribute(fretNote, mxFrameNote, 'fingering', 'fingering') return mxFrameNote @@ -6504,8 +6504,8 @@ def lyricToXml(self, ly: note.Lyric): ''' mxLyric = Element('lyric') if not ly.isComposite: - _setTagTextFromAttribute(ly, mxLyric, 'syllabic') - _setTagTextFromAttribute(ly, mxLyric, 'text', forceEmpty=True) + _setTagTextFromAttribute(ly, mxLyric, 'syllabic', 'syllabic') + _setTagTextFromAttribute(ly, mxLyric, 'text', 'text', forceEmpty=True) else: # composite must have at least one component if t.TYPE_CHECKING: @@ -6519,8 +6519,8 @@ def lyricToXml(self, ly: note.Lyric): mxElision = SubElement(mxLyric, 'elision') if component.elisionBefore: mxElision.text = component.elisionBefore - _setTagTextFromAttribute(component, mxLyric, 'syllabic') - _setTagTextFromAttribute(component, mxLyric, 'text', forceEmpty=True) + _setTagTextFromAttribute(component, mxLyric, 'syllabic', 'syllabic') + _setTagTextFromAttribute(component, mxLyric, 'text', 'text', forceEmpty=True) # TODO: extend # TODO: laughing @@ -7083,7 +7083,7 @@ def keySignatureToXml(self, keyOrKeySignature): # TODO: cancel seta(keyOrKeySignature, mxKey, 'fifths', 'sharps') if hasattr(keyOrKeySignature, 'mode') and keyOrKeySignature.mode is not None: - seta(keyOrKeySignature, mxKey, 'mode') + seta(keyOrKeySignature, mxKey, 'mode', 'mode') else: # choice... non-traditional-key... @@ -7163,7 +7163,7 @@ def clefToXml(self, clefObj): mxSign = SubElement(mxClef, 'sign') mxSign.text = sign - _setTagTextFromAttribute(clefObj, mxClef, 'line') + _setTagTextFromAttribute(clefObj, mxClef, 'line', 'line') if clefObj.octaveChange not in (0, None): _setTagTextFromAttribute(clefObj, mxClef, 'clef-octave-change', 'octaveChange') diff --git a/music21/romanText/clercqTemperley.py b/music21/romanText/clercqTemperley.py index 139b388e6..154422b07 100644 --- a/music21/romanText/clercqTemperley.py +++ b/music21/romanText/clercqTemperley.py @@ -409,9 +409,7 @@ def parse(self, textFile: str|pathlib.Path): raise CTSongException( f'Invalid File Format; must be string or text file: {textFile}') - lines = [e for e in lines if len(e) != 0] - for i in range(len(lines)): - lines[i] = lines[i].strip() + lines = [e.strip() for e in lines if len(e) != 0] self.lines = lines pieceString = '\n'.join(lines) diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index fb9c96370..9005376d5 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -1321,10 +1321,7 @@ def isConcrete(self): To be concrete, a Scale must have a defined tonic. An abstract Scale is not Concrete ''' - if self.tonic is None: - return False - else: - return True + return self.tonic is not None def __eq__(self, other): ''' @@ -1358,15 +1355,14 @@ def __eq__(self, other): if not self.isConcrete or not other.isConcrete: # if tonic is none, then we automatically do an abstract comparison return self._abstract == other._abstract - else: - if (isinstance(other, self.__class__) - and isinstance(self, other.__class__) - and self._abstract == other._abstract - and self.boundRange == other.boundRange - and self.tonic == other.tonic): - return True - else: - return False + + if (isinstance(other, self.__class__) + and isinstance(self, other.__class__) + and self._abstract == other._abstract + and self.boundRange == other.boundRange + and self.tonic == other.tonic): + return True + return False def __hash__(self): return id(self) >> 4 diff --git a/music21/tree/verticality.py b/music21/tree/verticality.py index ee091e791..c7e109534 100644 --- a/music21/tree/verticality.py +++ b/music21/tree/verticality.py @@ -762,7 +762,7 @@ def makeElement( pitchBust = 0 # used if removeRedundantPitches is False. # noinspection PyShadowingNames - def newNote(ts, n: note.Note) -> note.Note: + def newNote(ts: spans.PitchedTimespan, n: note.Note) -> note.Note: ''' Make a copy of the note and clear some settings ''' @@ -809,7 +809,7 @@ def newNote(ts, n: note.Note) -> note.Note: return nNew # noinspection PyShadowingNames - def conditionalAdd(ts, n: note.Note) -> None: + def conditionalAdd(ts: spans.PitchedTimespan, n: note.Note) -> None: ''' Add an element only if it is not already in the chord.