def capuaRuleFourB(srcStream): ''' See capuaRuleOne for precise instructions. Applies more probable interpretation of Capua's fourth rule to the given srcStream, i.e. if a descending minor third is followed by a descending major second, the intervals will be changed to a major third followed by a minor second. Also copies any relevant accidental to note.editorial.misc under "saved-accidental" and changes note.editorial.color for rule 4 (orange green orange). returns the number of times a note was changed. ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(0, len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or \ n2.isRest or \ n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if n1.accidental is not None or \ n3.accidental is not None: continue ### never seems to improve things... if n2.step == "A" or n2.step == "D": continue # e.g., D F G => D F# G or G Bb C => G B C if i1.directedName == "m3" and \ i2.directedName == "M2": numChanged += 1 if ("capua" in n2.editorial.misc): n2.editorial.misc['capua_rule_number'] += RULE_FOUR_B else: n2.editorial.misc['capua_rule_number'] = RULE_FOUR_B if (n2.accidental is not None and n2.accidental.name == "flat"): n2.editorial.misc["saved-accidental"] = n2.accidental n2.accidental = None n2.editorial.ficta = pitch.Accidental("natural") n2.editorial.misc["capua-ficta"] = pitch.Accidental("natural") n1.editorial.color = "orange" n2.editorial.color = "green" n3.editorial.color = "orange" else: n2.editorial.ficta = pitch.Accidental("sharp") n2.editorial.misc["capua-ficta"] = pitch.Accidental("sharp") n1.editorial.color = "orange" n2.editorial.color = "green" n3.editorial.color = "orange" return numChanged
def capuaRuleOne(srcStream): ''' Applies Nicolaus de Capua's first rule to the given srcStream, i.e. if a line descends a major second then ascends back to the original note, the major second is made into a minor second. Also copies the relevant accidentals into `Note.editorial.misc["saved-accidental"]` and changes `Note.editorial.color` for rule 1 (blue green blue). The relevant Rule number is also stored in `Note.editorial.misc['capua_rule_number']` which can be got out by OR-ing this. Returns the number of notes that were changed (not counting notes whose colors were changed). ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(0, len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if (n1.isRest or n2.isRest or n3.isRest): continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if (n1.pitch.accidental is not None or n3.pitch.accidental is not None): continue ### never seems to improve things... if n2.step == "A" or n2.step == "D": continue ## e.g. G, F, G => G, F#, G if i1.directedName == "M-2" and \ i2.directedName == "M2": numChanged += 1 if ("capua" in n2.editorial.misc): n2.editorial.misc['capua_rule_number'] += RULE_ONE else: n2.editorial.misc['capua_rule_number'] = RULE_ONE if (n2.pitch.accidental is not None and n2.pitch.accidental.name == "flat"): n2.editorial.misc["saved-accidental"] = n2.pitch.accidental n2.pitch.accidental = None n2.editorial.ficta = pitch.Accidental("natural") n2.editorial.misc["capua-ficta"] = pitch.Accidental("natural") n1.editorial.color = "blue" n2.editorial.color = "forestGreen" n3.editorial.color = "blue" else: n2.editorial.ficta = pitch.Accidental("sharp") n2.editorial.misc["capua-ficta"] = pitch.Accidental("sharp") n1.editorial.color = "blue" n2.editorial.color = "ForestGreen" n3.editorial.color = "blue" return numChanged
def capuaRuleOne(srcStream): ''' Applies Nicolaus de Capua's first rule to the given srcStream, i.e. if a line descends a major second then ascends back to the original note, the major second is made into a minor second. Also copies the relevant accidentals into `Note.editorial.savedAccidental` and changes `Note.style.color` for rule 1 (blue green blue). The relevant Rule number is also stored in `Note.editorial.capuaRuleNumber']` which can be got out by OR-ing this. Returns the number of notes that were changed (not counting notes whose colors were changed). ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or n2.isRest or n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if (n1.pitch.accidental is not None or n3.pitch.accidental is not None): continue # never seems to improve things... if n2.step == 'A' or n2.step == 'D': continue # e.g. G, F, G => G, F#, G if (i1.directedName == 'M-2' and i2.directedName == 'M2'): numChanged += 1 if 'capuaRuleNumber' in n2.editorial: n2.editorial.capuaRuleNumber += RULE_ONE else: n2.editorial.capuaRuleNumber = RULE_ONE if n2.pitch.accidental is not None and n2.pitch.accidental.name == 'flat': n2.editorial.savedAccidental = n2.pitch.accidental n2.pitch.accidental = None n2.editorial.ficta = pitch.Accidental('natural') n2.editorial.capuaFicta = pitch.Accidental('natural') n1.style.color = 'blue' n2.style.color = 'forestGreen' n3.style.color = 'blue' else: n2.editorial.ficta = pitch.Accidental('sharp') n2.editorial.capuaFicta = pitch.Accidental('sharp') n1.style.color = 'blue' n2.style.color = 'ForestGreen' n3.style.color = 'blue' return numChanged
def capuaRuleFourB(srcStream): ''' See capuaRuleOne for precise instructions. Applies more probable interpretation of Capua's fourth rule to the given srcStream, i.e. if a descending minor third is followed by a descending major second, the intervals will be changed to a major third followed by a minor second. Also copies any relevant accidental to note.editorial.savedAccidental and changes note.style.color for rule 4 (orange green orange). returns the number of times a note was changed. ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or n2.isRest or n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if (n1.pitch.accidental is not None or n3.pitch.accidental is not None): continue # never seems to improve things... if n2.step == 'A' or n2.step == 'D': continue # e.g., D F G => D F# G or G Bb C => G B C if i1.directedName == 'm3' and i2.directedName == 'M2': numChanged += 1 if 'capuaRuleNumber' in n2.editorial: n2.editorial.capuaRuleNumber += RULE_FOUR_B else: n2.editorial.capuaRuleNumber = RULE_FOUR_B if n2.pitch.accidental is not None and n2.pitch.accidental.name == 'flat': n2.editorial.savedAccidental = n2.pitch.accidental n2.pitch.accidental = None n2.editorial.ficta = pitch.Accidental('natural') n2.editorial.capuaFicta = pitch.Accidental('natural') n1.style.color = 'orange' n2.style.color = 'green' n3.style.color = 'orange' else: n2.editorial.ficta = pitch.Accidental('sharp') n2.editorial.capuaFicta = pitch.Accidental('sharp') n1.style.color = 'orange' n2.style.color = 'green' n3.style.color = 'orange' return numChanged
def capuaRuleFourA(srcStream): ''' See capuaRuleOne for precise instructions. Applies one interpretation of Capua's fourth rule to the given srcStream, i.e. if a descending minor third is followed by a descending major second, the intervals will be changed to a major third followed by a minor second. Also changes note.editorial.color for rule 4 (orange green orange). returns the number of notes that were changed This rule is a less likely interpretation of the ambiguous rule 4, thus applyCapuaToStream uses capuaRuleFourB instead. ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(0, len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or \ n2.isRest or \ n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if n1.accidental is not None or \ n2.accidental is not None or \ n3.accidental is not None: continue ### never seems to improve things... if n2.step == "A" or n2.step == "D": continue # e.g., D B A => D Bb A if i1.directedName == "m-3" and \ i2.directedName == "M-2": numChanged += 1 if ("capua" in n2.editorial.misc): n2.editorial.misc['capua_rule_number'] += RULE_FOUR_A else: n2.editorial.misc['capua_rule_number'] = RULE_FOUR_A n2.editorial.ficta = pitch.Accidental("flat") n2.editorial.misc["capua-ficta"] = pitch.Accidental("flat") n1.editorial.color = "orange" n2.editorial.color = "ForestGreen" n3.editorial.color = "orange" return numChanged
def capuaRuleThree(srcStream): ''' See capuaRuleOne for precise instructions. Applies Capua's third rule to the given srcStream, i.e. if there is a descending major third followed by an ascending major second, the second note will be made a half-step higher so that there is a descending minor third followed by an ascending minor second. Also changes note.editorial.color for rule 3 (pink green pink). returns the number of times a note was changed ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(0, len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or \ n2.isRest or \ n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if n1.accidental is not None or \ n2.accidental is not None or \ n3.accidental is not None: continue ### never seems to improve things... if n2.step == "A" or n2.step == "D": continue # e.g., E C D => E C# D if i1.directedName == "M-3" and \ i2.directedName == "M2": numChanged += 1 if ("capua" in n2.editorial.misc): n2.editorial.misc['capua_rule_number'] += RULE_THREE else: n2.editorial.misc['capua_rule_number'] = RULE_THREE n2.editorial.ficta = pitch.Accidental("sharp") n2.editorial.misc["capua-ficta"] = pitch.Accidental("sharp") n1.editorial.color = "DeepPink" n2.editorial.color = "ForestGreen" n3.editorial.color = "DeepPink" return numChanged
def capuaRuleFourA(srcStream): ''' See capuaRuleOne for precise instructions. Applies one interpretation of Capua's fourth rule to the given srcStream, i.e. if a descending minor third is followed by a descending major second, the intervals will be changed to a major third followed by a minor second. Also changes note.style.color for rule 4 (orange green orange). returns the number of notes that were changed This rule is a less likely interpretation of the ambiguous rule 4, thus applyCapuaToStream uses capuaRuleFourB instead. ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or n2.isRest or n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if (n1.pitch.accidental is not None or n2.pitch.accidental is not None or n3.pitch.accidental is not None): continue # never seems to improve things... if n2.step == 'A' or n2.step == 'D': continue # e.g., D B A => D Bb A if i1.directedName == 'm-3' and i2.directedName == 'M-2': numChanged += 1 if 'capuaRuleNumber' in n2.editorial: n2.editorial.capuaRuleNumber += RULE_FOUR_A else: n2.editorial.capuaRuleNumber = RULE_FOUR_A n2.editorial.ficta = pitch.Accidental('flat') n2.editorial.capuaFicta = pitch.Accidental('flat') n1.style.color = 'orange' n2.style.color = 'ForestGreen' n3.style.color = 'orange' return numChanged
def capuaRuleThree(srcStream): ''' See capuaRuleOne for precise instructions. Applies Capua's third rule to the given srcStream, i.e. if there is a descending major third followed by an ascending major second, the second note will be made a half-step higher so that there is a descending minor third followed by an ascending minor second. Also changes note.style.color for rule 3 (pink green pink). returns the number of times a note was changed ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(len(ssn) - 2): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] if n1.isRest or n2.isRest or n3.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) if (n1.pitch.accidental is not None or n2.pitch.accidental is not None or n3.pitch.accidental is not None): continue # never seems to improve things... if n2.step == 'A' or n2.step == 'D': continue # e.g., E C D => E C# D if (i1.directedName == 'M-3' and i2.directedName == 'M2'): numChanged += 1 if 'capuaRuleNumber' in n2.editorial: n2.editorial.capuaRuleNumber += RULE_THREE else: n2.editorial.capuaRuleNumber = RULE_THREE n2.editorial.ficta = pitch.Accidental('sharp') n2.editorial.capuaFicta = pitch.Accidental('sharp') n1.style.color = 'DeepPink' n2.style.color = 'ForestGreen' n3.style.color = 'DeepPink' return numChanged
def _addAccidental(self, n, alter, pm, t): r''' helper function for all accidental types. >>> nToken = tinyNotation.NoteToken('BB--') >>> n = note.Note('B') >>> n.octave = 2 >>> tPost = nToken._addAccidental(n, -2, r'(\-+)', 'BB--') >>> tPost 'BB' >>> n.pitch.accidental <accidental double-flat> >>> nToken = tinyNotation.NoteToken('BB(--)') >>> nToken.isEditorial = True >>> n = note.Note('B') >>> n.octave = 2 >>> tPost = nToken._addAccidental(n, -2, r'(\-+)', 'BB--') >>> tPost 'BB' >>> n.editorial.ficta <accidental double-flat> ''' acc = pitch.Accidental(alter) if self.isEditorial: n.editorial.ficta = acc else: n.pitch.accidental = acc t = re.sub(pm, '', t) return t
def testMeasureCopyingB(self): from music21 import converter from music21 import pitch src = """m1 G: IV || b3 d: III b4 ii m2 v b2 III6 b3 iv6 b4 ii/o6/5 m3 i6/4 b3 V m4-5 = m2-3 m6-7 = m4-5 """ s = converter.parse(src, format='romantext') rnStream = s.flat.getElementsByClass('RomanNumeral') for elementNumber in [0, 6, 12]: self.assertEqual(rnStream[elementNumber + 4].figure, 'III6') self.assertEqual( str([str(p) for p in rnStream[elementNumber + 4].pitches]), "['A4', 'C5', 'F5']") x = rnStream[elementNumber + 4].pitches[2].accidental if x == None: x = pitch.Accidental('natural') self.assertEqual(x.alter, 0) self.assertEqual(rnStream[elementNumber + 5].figure, 'iv6') self.assertEqual( str([str(p) for p in rnStream[elementNumber + 5].pitches]), "['B-4', 'D5', 'G5']") self.assertEqual( rnStream[elementNumber + 5].pitches[0].accidental.displayStatus, True)
def accidentalFromAlter(self, alterElement): ''' return a :class:`~music21.pitch.Accidental` object from an <alter> tag. >>> ci = capella.fromCapellaXML.CapellaImporter() >>> alter = ci.domElementFromText('<alter step="-1"/>') >>> ci.accidentalFromAlter(alter) <accidental flat> The only known display type is "suppress" >>> alter = ci.domElementFromText('<alter step="2" display="suppress"/>') >>> acc = ci.accidentalFromAlter(alter) >>> acc <accidental double-sharp> >>> acc.displayType 'never' ''' if 'step' in alterElement._attrs: alteration = int(alterElement._attrs['step'].value) acc = pitch.Accidental(alteration) if 'display' in alterElement._attrs and alterElement._attrs[ 'display'].value == 'suppress': acc.displayType = 'never' return acc
def _toAccidental(self): ''' >>> from music21.figuredBass import notation as n >>> m1 = n.Modifier('#') >>> m2 = n.Modifier('-') >>> m3 = n.Modifier('n') >>> m4 = n.Modifier('+') #Raises pitch by semitone >>> m5 = n.Modifier('b') #acceptable for flat since note names not allowed >>> m1.accidental <accidental sharp> >>> m2.accidental <accidental flat> >>> m3.accidental <accidental natural> >>> m4.accidental <accidental sharp> >>> m5.accidental <accidental flat> ''' if not self.modifierString: return None a = pitch.Accidental() try: a.set(self.modifierString) except pitch.AccidentalException: try: newModifierString = specialModifiers[self.modifierString] except KeyError: raise ModifierException( "Figure modifier unsupported in music21: %s." % self.modifierString) a.set(newModifierString) return a
def getOnePitchFromPosition(self, pos): ''' get one pitch from a position... >>> nwt = noteworthy.translate.NoteworthyTranslator() >>> nwt.currentClef = 'BASS' >>> p = nwt.getOnePitchFromPosition('b3') >>> p <music21.pitch.Pitch G-3> >>> p.ps 54.0 ''' accidental = "" if pos[0] in ['n', 'b', '#', 'x', 'v']: accidental = pos[0] pos = pos[1:] if accidental == 'b': accidental = '-' elif accidental == 'x': accidental = '##' elif accidental == 'v': accidental = "--" positionNote = int(pos) (noteStep, octave) = self.getStepAndOctaveFromPosition(positionNote) p = pitch.Pitch() p.step = noteStep p.octave = octave pname = p.nameWithOctave if accidental != "": p.accidental = pitch.Accidental(accidental) self.activeAccidentals[pname] = accidental ## previous accidental in same bar that is still active elif pname in self.activeAccidentals: p.accidental = pitch.Accidental(self.activeAccidentals[pname]) else: stepAccidental = self.currentKey.accidentalByStep(noteStep) if stepAccidental is not None: p.accidental = stepAccidental return p
def _addAccidental(self, n, alter, pm, t): ''' helper function for all accidental types. ''' acc = pitch.Accidental(alter) if self.isEditorial: n.editorial.ficta = acc else: n.pitch.accidental = acc t = re.sub(pm, '', t) return t
def testGetAccidentalCountIntermediate(self): s = stream.Stream() s.append(note.Note("C4")) # no accidental s.append(note.Note("C#4")) # sharp s.append(note.Note("D-4")) # flat self.assertEqual(getAccidentalCount(s), {'flat': 1, 'sharp': 1}) self.assertEqual(getAccidentalCount(s, True), {'flat': 1, 'sharp': 1, 'natural': 1}) note4 = note.Note("C4") self.assertIsNone(note4.pitch.accidental) note4.pitch.accidental = pitch.Accidental('natural') # add a natural accidental s.append(note4) self.assertEqual(getAccidentalCount(s), {'flat': 1, 'sharp': 1, 'natural': 1})
def modifyPitch(self, pitchToAlter, inPlace=False): ''' Given a :class:`~music21.pitch.Pitch`, modify its :attr:`~music21.pitch.Pitch.accidental` given the Modifier's :attr:`~music21.figuredBass.notation.Modifier.accidental`. >>> from music21 import pitch >>> from music21.figuredBass import notation >>> m1 = notation.Modifier('#') >>> m2 = notation.Modifier('-') >>> m3 = notation.Modifier('n') >>> p1a = pitch.Pitch('D5') >>> m1.modifyPitch(p1a) # Sharp <music21.pitch.Pitch D#5> >>> m2.modifyPitch(p1a) # Flat <music21.pitch.Pitch D-5> >>> p1b = pitch.Pitch('D#5') >>> m3.modifyPitch(p1b) <music21.pitch.Pitch D5> OMIT_FROM_DOCS >>> m4 = notation.Modifier('##') >>> m5 = notation.Modifier('--') >>> p2 = pitch.Pitch('F5') >>> m4.modifyPitch(p2) # Double Sharp <music21.pitch.Pitch F##5> >>> m5.modifyPitch(p2) # Double Flat <music21.pitch.Pitch F--5> ''' if not inPlace: pitchToAlter = copy.deepcopy(pitchToAlter) if self.accidental == None: return pitchToAlter if self.accidental.alter == 0.0: pitchToAlter.accidental = self.accidental else: if pitchToAlter.accidental == None: pitchToAlter.accidental = self.accidental else: newAccidental = pitch.Accidental() newAlter = pitchToAlter.accidental.alter + self.accidental.alter try: newAccidental.set(newAlter) pitchToAlter.accidental = newAccidental except pitch.AccidentalException: raise ModifierException( "Resulting pitch accidental unsupported in music21.") return pitchToAlter
def testStreamLilySemiComplex(self): from copy import deepcopy from music21 import meter, note, stream, pitch, duration a = stream.Stream() ts = meter.TimeSignature("3/8") b = stream.Stream() q = note.EighthNote() dur1 = duration.Duration() dur1.type = "eighth" tup1 = duration.Tuplet() tup1.tupletActual = [5, dur1] tup1.tupletNormal = [3, dur1] q.octave = 2 q.duration.appendTuplet(tup1) for i in range(0, 5): b.append(deepcopy(q)) b.elements[i].accidental = pitch.Accidental(i - 2) b.elements[0].duration.tuplets[0].type = "start" b.elements[-1].duration.tuplets[0].type = "stop" b2temp = b.elements[2] c = b2temp.editorial c.comment.text = "a real C" bestC = b.bestClef(allowTreble8vb=True) a.insert(bestC) a.insert(ts) a.insert(b) conv = LilypondConverter() outStr = conv.fromObject(a) testStr = u'\n { \\clef "bass" \\time 3/8 \n { \\times 3/5 {ceses,8 ces,8 c,8_"a real C" cis,8 cisis,8} } }' # for i in range(len(outStr)): # self.assertEqual(outStr[i], testStr[i]) # print outStr # print testStr self.assertEqual(outStr, testStr)
def toAccidental(self, value, accidentalObject=None): ''' Converts a string to an accidental (or adds it to the current accidentalObject). If accidentalObject passed in is None returns the new accidental >>> from music21 import * >>> importer = lily.translate.LilypondImporter() >>> acc = importer.toAccidental('eses') >>> acc <accidental double-flat> >>> acc2 = importer.toAccidental('eh!?') >>> acc2 <accidental half-flat> >>> acc2.displayType 'always' >>> acc2.displayStyle 'parentheses' ''' if accidentalObject is None: returnAccidental = True from music21 import pitch accidentalObject = pitch.Accidental() else: returnAccidental = False if value.endswith('?'): value = value[0:len(value) - 1] accidentalObject.displayStyle = "parentheses" if value.endswith('!'): value = value[0:len(value) - 1] accidentalObject.displayType = "always" if value in self.accidentalConvert: accidentalObject.name = self.accidentalConvert[value] else: raise LilyTranslateException( 'Cannot convert this value to an accidental %s.' % value) if returnAccidental is True: return accidentalObject
def visit_body(self, node, children): ch = chant.Chant() curSection = chant.Section() curClef = chant.Clef() curGABCClef = None # First pass: add measurs for word in children: if not isinstance(word, chant.Word): raise Exception('Quoi?') curSection.append(word) # Scope of accidentals ends with word boundaries curClefHasFlat = curGABCClef in ['cb1', 'cb2', 'cb3', 'cb4'] bIsFlat = False or curClefHasFlat bIsNatural = False eIsFlat = False eIsNatural = False # Update the pitches of all notes based on the the clef # and accidentals for el in word.flat: if isinstance(el, note.Note): if curGABCClef is None: raise MissingClef('Missing clef! Cannot process notes without a clef.') position = el.editorial.gabcPosition stepWithOctave = gabcPositionToStep(position, curGABCClef) el.nameWithOctave = stepWithOctave if bIsNatural and el.step == 'B': el.pitch.accidental = pitch.Accidental('natural') elif eIsNatural and el.step == 'E': el.pitch.accidental = pitch.Accidental('natural') elif bIsFlat and el.step == 'B': el.pitch.accidental = pitch.Accidental('flat') elif eIsFlat and el.step == 'E': el.pitch.accidental = pitch.Accidental('flat') elif isinstance(el, chant.Alteration): if curGABCClef is None: raise MissingClef('Cannot process notes without a clef.') position = el.editorial.gabcPosition step = gabcPositionToStep(position, curGABCClef) el.pitch = pitch.Pitch(step) # Reset alterations bIsFlat = False or curClefHasFlat bIsNatural = False eIsFlat = False eIsNatural = False # Update if isinstance(el, chant.Flat) and el.pitch.step == 'E': eIsFlat = True elif isinstance(el, chant.Flat) and el.pitch.step == 'B': bIsFlat = True elif isinstance(el, chant.Natural) and el.pitch.step == 'B': bIsNatural = True elif isinstance(el, chant.Natural) and el.pitch.step == 'E': eIsNatural = True # Scope of accidentals ends at breathmarks elif isinstance(el, chant.Pausa): bIsFlat = False or curClefHasFlat bIsNatural = False eIsFlat = False eIsNatural = False # Intermediate sections start (!) at pausa finalis (double barlines) # because annotations below them always refer to the next sections. # The very last pausa finalis is part of the last section though if isinstance(el, chant.PausaFinalis): if not word == children[-1]: curSection.remove(word) ch.append(curSection) curSection = chant.Section() curSection.append(word) else: ch.append(curSection) curSection = chant.Section() elif isinstance(el, chant.Clef): curClef = el curGABCClef = curClef.editorial.gabc elif isinstance(el, chant.Annotation): pass else: raise Exception('Unknown element') if len(curSection.flat) > 0: ch.append(curSection) # ch.joinTextAcrossPausas() return ch
def _getNote(self): if self._note is not None: return self._note noteObj = None storedtie = None stringRep = self.stringRep storedDict = self.storedDict if stringRep is None: raise TinyNotationException( 'Cannot return a note without some parameters') if self.PRECTIE.match(stringRep): environLocal.printDebug('Found Front Tie') stringRep = self.PRECTIE.sub("", stringRep) storedtie = tie.Tie("stop") storedDict['lastNoteTied'] = False elif 'lastNoteTied' in storedDict and storedDict[ 'lastNoteTied'] is True: storedtie = tie.Tie("stop") storedDict['lastNoteTied'] = False x = self.customPitchMatch(stringRep, storedDict) if x is not None: noteObj = x elif (self.REST.match(stringRep) is not None): # rest noteObj = note.Rest() elif (self.OCTAVE2.match(stringRep)): # BB etc. nn = self.OCTAVE2.match(stringRep) noteObj = self._getPitch(nn, 3 - len(nn.group(1))) elif (self.OCTAVE3.match(stringRep)): noteObj = self._getPitch(self.OCTAVE3.match(stringRep), 3) elif (self.OCTAVE5.match(stringRep)): # must match octave 5 then 4! nn = self.OCTAVE5.match(stringRep) noteObj = self._getPitch(nn, 4 + len(nn.group(2))) elif (self.OCTAVE4.match(stringRep)): noteObj = self._getPitch(self.OCTAVE4.match(stringRep), 4) else: raise TinyNotationException( "could not get pitch information from " + str(stringRep)) if storedtie: noteObj.tie = storedtie ## get duration usedLastDuration = False if (self.TYPE.search(stringRep)): typeNum = self.TYPE.search(stringRep).group(1) if (typeNum == "0"): ## special case = full measure + fermata if 'barDuration' in storedDict: noteObj.duration = storedDict['barDuration'] newFerm = expressions.Fermata() noteObj.expressions.append(newFerm) else: noteObj.duration.type = duration.typeFromNumDict[int(typeNum)] else: if 'lastDuration' in storedDict: noteObj.duration = copy.deepcopy(storedDict['lastDuration']) usedLastDuration = True if (noteObj.duration.tuplets): noteObj.duration.tuplets[0].type = "" # if it continues a tuplet it cannot be start; maybe end ## get dots; called out because subclassable self.getDots(stringRep, noteObj) ## get ties if self.TIE.search(stringRep): environLocal.printDebug('Found Tie Tie') storedDict['lastNoteTied'] = True if noteObj.tie is None: noteObj.tie = tie.Tie("start") else: noteObj.tie.type = 'continue' ## use dict to set tuplets if ((('inTrip' in storedDict and storedDict['inTrip'] == True) or ('inQuad' in storedDict and storedDict['inQuad'] == True)) and usedLastDuration == False): newTup = duration.Tuplet() newTup.durationActual.type = noteObj.duration.type newTup.durationNormal.type = noteObj.duration.type if 'inQuad' in storedDict and storedDict['inQuad'] == True: newTup.numNotesActual = 4.0 newTup.numNotesNormal = 3.0 if 'beginTuplet' in storedDict and storedDict[ 'beginTuplet'] == True: newTup.type = "start" noteObj.duration.appendTuplet(newTup) if ((('inTrip' in storedDict and storedDict['inTrip'] == True) or ('inQuad' in storedDict and storedDict['inQuad'] == True)) and ('endTuplet' in storedDict and storedDict['endTuplet'] == True)): noteObj.duration.tuplets[0].type = "stop" storedDict['lastDuration'] = noteObj.duration ## get accidentals if (isinstance(noteObj, note.Note)): if (self.EDSHARP.search(stringRep)): # must come before sharp alter = len(self.EDSHARP.search(stringRep).group(1)) acc1 = pitch.Accidental(alter) noteObj.editorial.ficta = acc1 noteObj.editorial.misc['pmfc-ficta'] = acc1 elif (self.EDFLAT.search(stringRep)): # must come before flat alter = -1 * len(self.EDFLAT.search(stringRep).group(1)) acc1 = pitch.Accidental(alter) noteObj.editorial.ficta = acc1 noteObj.editorial.misc['pmfc-ficta'] = acc1 elif (self.EDNAT.search(stringRep)): acc1 = pitch.Accidental("natural") noteObj.editorial.ficta = acc1 noteObj.editorial.misc['pmfc-ficta'] = acc1 noteObj.accidental = acc1 elif (self.SHARP.search(stringRep)): alter = len(self.SHARP.search(stringRep).group(1)) noteObj.accidental = pitch.Accidental(alter) elif (self.FLAT.search(stringRep)): alter = -1 * len(self.FLAT.search(stringRep).group(1)) noteObj.accidental = pitch.Accidental(alter) self.customNotationMatch(noteObj, stringRep, storedDict) if self.ID_EL.search(stringRep): noteObj.id = self.ID_EL.search(stringRep).group(1) if self.LYRIC.search(stringRep): noteObj.lyric = self.LYRIC.search(stringRep).group(1) self._note = noteObj return self._note
def partPari(show = True): ''' generate the score of Arvo Pärt's "Pari Intervallo" algorithmically using music21.scale.ConcreteScale() to simulate Tintinabulation. ''' s = stream.Score() cminor = key.Key('c') #real Paert main = converter.parse("tinynotation: 4/4 E-1 C D E- F G F E- D C D E- G A- F G E- F G F E- D F G c B- c G A- B- c B- A- B- G c e- d c d c B- A- G F E- F G c E- F G E- D E- F E- D C E- G F E- C F E- D C E- D C D C~ C") # fake Paert #main = converter.parse("E-1 F G A- G F c d e- G A- F E- D d e- c B- A- c d A- G F G F A- B- A- c d A- B- c B- A- G F G F E-~ E-", '4/4') main.__class__ = stream.Part main.transpose('P8', inPlace=True) main.insert(0, cminor) main.insert(0, instrument.Recorder()) bass = copy.deepcopy(main.flat) for n in bass.notes: n.pitch.diatonicNoteNum = n.pitch.diatonicNoteNum - 9 if (n.pitch.step == 'A' or n.pitch.step == 'B') and n.pitch.octave == 2: n.accidental = pitch.Accidental('natural') else: n.accidental = cminor.accidentalByStep(n.step) if n.offset == (2-1) * 4 or n.offset == (74-1) * 4: n.pitch = pitch.Pitch("C3") # exceptions to rule elif n.offset == (73 - 1) * 4: n.tie = None n.pitch = pitch.Pitch("C3") top = copy.deepcopy(main.flat) main.insert(0, clef.Treble8vbClef()) middle = copy.deepcopy(main.flat) cMinorArpeg = scale.ConcreteScale(pitches = ["C2","E-2","G2"]) # dummy test on other data #myA = pitch.Pitch("A2") #myA.microtone = -15 #cMinorArpeg = scale.ConcreteScale(pitches = ["C2", "E`2", "F~2", myA]) lastNote = top.notes[-1] top.remove(lastNote) for n in top: if 'Note' in n.classes: n.pitch = cMinorArpeg.next(n.pitch, stepSize=2) if n.offset != (73-1)*4.0: # m. 73 is different n.duration.quarterLength = 3.0 top.insert(n.offset + 3, note.Rest()) else: n.duration.quarterLength = 6.0 n.tie = None r1 = note.Rest(type = 'half') top.insertAndShift(0, r1) top.getElementsByClass(key.Key)[0].setOffsetBySite(top, 0) lastNote = middle.notes[-1] middle.remove(lastNote) for n in middle: if 'Note' in n.classes: n.pitch = cMinorArpeg.next(n.pitch, direction=scale.DIRECTION_DESCENDING, stepSize=2) if n.offset != (73-1)*4.0: # m. 73 is different n.duration.quarterLength = 3.0 middle.insert(n.offset + 3, note.Rest()) else: n.duration.quarterLength = 5.0 n.tie = None r2 = note.Rest(quarterLength = 3.0) middle.insertAndShift(0, r2) middle.getElementsByClass(key.Key)[0].setOffsetBySite(middle, 0) ttied = top.makeMeasures().makeTies(inPlace=False) mtied = middle.makeMeasures().makeTies(inPlace=False) bass.makeMeasures(inPlace = True) main.makeMeasures(inPlace = True) s.insert(0, ttied) s.insert(0, main) s.insert(0, mtied) s.insert(0, bass) for p in s.parts: p.getElementsByClass(stream.Measure)[-1].rightBarline = bar.Barline('final') if show == True: s.show()
def toPart(volpianoText, *, breaksToLayout=False): # noinspection PyShadowingNames ''' Returns a music21 Part from volpiano text. >>> veniSancti = volpiano.toPart('1---c--d---f--d---ed--c--d---f' ... + '---g--h--j---hgf--g--h---') >>> veniSancti.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note C> {1.0} <music21.note.Note D> {2.0} <music21.note.Note F> {3.0} <music21.note.Note D> {4.0} <music21.note.Note E> {5.0} <music21.note.Note D> {6.0} <music21.volpiano.Neume <music21.note.Note E><music21.note.Note D>> {6.0} <music21.note.Note C> {7.0} <music21.note.Note D> {8.0} <music21.note.Note F> {9.0} <music21.note.Note G> {10.0} <music21.note.Note A> {11.0} <music21.note.Note B> {12.0} <music21.note.Note A> {13.0} <music21.note.Note G> {14.0} <music21.note.Note F> {15.0} <music21.volpiano.Neume <music21.note.Note A><music21.note.Note G>> {15.0} <music21.note.Note G> {16.0} <music21.note.Note A> Clefs! >>> clefTest = volpiano.toPart('1---c--2---c') >>> clefTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note C> {1.0} <music21.clef.BassClef> {1.0} <music21.note.Note E> >>> for n in clefTest.recurse().notes: ... n.nameWithOctave 'C4' 'E2' Flats and Naturals: >>> accTest = volpiano.toPart('1---e--we--e--We--e') >>> [n.name for n in accTest.recurse().notes] ['E', 'E-', 'E-', 'E', 'E'] Breaks and barlines >>> breakTest = volpiano.toPart('1---e-7-e-77-e-777-e-3-e-4') >>> breakTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note E> {1.0} <music21.volpiano.LineBreak object at 0x105250fd0> {1.0} <music21.note.Note E> {2.0} <music21.volpiano.PageBreak object at 0x105262128> {2.0} <music21.note.Note E> {3.0} <music21.volpiano.ColumnBreak object at 0x105262240> {3.0} <music21.note.Note E> {4.0} <music21.bar.Barline type=regular> {4.0} <music21.stream.Measure 0 offset=4.0> {0.0} <music21.note.Note E> {1.0} <music21.bar.Barline type=double> As layout objects using breaksToLayout=True >>> breakTest = volpiano.toPart('1---e-7-e-77-e-777-e-3-e-4', breaksToLayout=True) >>> breakTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note E> {1.0} <music21.layout.SystemLayout> {1.0} <music21.note.Note E> {2.0} <music21.layout.PageLayout> {2.0} <music21.note.Note E> {3.0} <music21.volpiano.ColumnBreak object at 0x105262240> {3.0} <music21.note.Note E> {4.0} <music21.bar.Barline type=regular> {4.0} <music21.stream.Measure 0 offset=4.0> {0.0} <music21.note.Note E> {1.0} <music21.bar.Barline type=double> Liquescence test: >>> breakTest = volpiano.toPart('1---e-E-') >>> breakTest.recurse().notes[0].editorial.liquescence False >>> breakTest.recurse().notes[0].notehead 'normal' >>> breakTest.recurse().notes[1].editorial.liquescence True >>> breakTest.recurse().notes[1].notehead 'x' Changed in v5.7 -- corrected spelling of liquescence. ''' p = stream.Part() m = stream.Measure() currentMeasure = m currentNeumeSpanner = None noteThatWouldGoInSpanner = None lastClef = clef.TrebleClef() continuousNumberOfBreakTokens = 0 bIsFlat = False eIsFlat = False for token in volpianoText: if token == '7': continuousNumberOfBreakTokens += 1 continue elif continuousNumberOfBreakTokens > 0: if not breaksToLayout: # default breakClass = classByNumBreakTokens[ continuousNumberOfBreakTokens] breakToken = breakClass() # pylint: disable=not-callable else: breakClass = classByNumBreakTokensLayout[ continuousNumberOfBreakTokens] if continuousNumberOfBreakTokens < 3: breakToken = breakClass(isNew=True) # pylint: disable=not-callable else: breakToken = breakClass() # pylint: disable=not-callable currentMeasure.append(breakToken) continuousNumberOfBreakTokens = 0 if token == '-': noteThatWouldGoInSpanner = None if currentNeumeSpanner: currentMeasure.append(currentNeumeSpanner) currentNeumeSpanner = None continue if token in '1234': noteThatWouldGoInSpanner = None currentNeumeSpanner = None if token in '12': if token == '1': c = clef.TrebleClef() else: c = clef.BassClef() lastClef = c m.append(c) elif token in '34': bl = bar.Barline() if token == '4': bl.type = 'double' m.rightBarline = bl p.append(m) m = stream.Measure() elif token in normalPitches or token in liquescentPitches: n = note.Note() n.stemDirection = 'noStem' if token in normalPitches: distanceFromLowestLine = normalPitches.index(token) - 5 n.editorial.liquescence = False else: distanceFromLowestLine = liquescentPitches.index(token) - 5 n.notehead = 'x' n.editorial.liquescence = True clefLowestLine = lastClef.lowestLine diatonicNoteNum = clefLowestLine + distanceFromLowestLine n.pitch.diatonicNoteNum = diatonicNoteNum if n.pitch.step == 'B' and bIsFlat: n.pitch.accidental = pitch.Accidental('flat') elif n.pitch.step == 'E' and eIsFlat: n.pitch.accidental = pitch.Accidental('flat') m.append(n) if noteThatWouldGoInSpanner is not None: currentNeumeSpanner = Neume([noteThatWouldGoInSpanner, n]) noteThatWouldGoInSpanner = None else: noteThatWouldGoInSpanner = n elif token in accidentalTokens: if token.lower() in eflatTokens and token in naturalTokens: eIsFlat = False elif token.lower() in bflatTokens and token in naturalTokens: bIsFlat = False elif token.lower() in eflatTokens and token in flatTokens: eIsFlat = True elif token.lower() in bflatTokens and token in flatTokens: bIsFlat = True else: # pragma: no cover raise VolpianoException('Unknown accidental: ' + token + ': Should not happen') if continuousNumberOfBreakTokens > 0: breakClass = classByNumBreakTokens[continuousNumberOfBreakTokens] breakToken = breakClass() # pylint: disable=not-callable currentMeasure.append(breakToken) if m: p.append(m) return p
def capuaRuleTwo(srcStream): ''' See capuaRuleOne for precise instructions. Applies Capua's second rule to the given srcStream, i.e. if four notes are ascending with the pattern M2 m2 M2, the intervals shall be made M2 M2 m2. Also changes note.editorial.color for rule 2 (purple purple green purple). returns the number of times any note was changed ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(0, len(ssn) - 3): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] n4 = ssn[i + 3] if n1.isRest or \ n2.isRest or \ n3.isRest or \ n4.isRest: continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) i3 = interval.notesToInterval(n3, n4) if n1.accidental is not None or \ n2.accidental is not None or \ n4.accidental is not None: continue ### never seems to improve things... if n3.step == "A" or n3.step == "D": continue # e.g., D E F G => D E F# G # or F A Bb C => F A B C if i1.directedName == "M2" and \ i2.directedName == "m2" and \ i3.directedName == "M2": numChanged += 1 if ("capua" in n3.editorial.misc): n3.editorial.misc['capua_rule_number'] += RULE_TWO else: n3.editorial.misc['capua_rule_number'] = RULE_TWO if (n3.accidental is not None and n3.accidental.name == "flat"): n3.editorial.misc["saved-accidental"] = n3.accidental n3.accidental = None n3.editorial.ficta = pitch.Accidental("natural") n3.editorial.misc["capua-ficta"] = pitch.Accidental("natural") n1.editorial.color = "purple" n2.editorial.color = "purple" n3.editorial.color = "ForestGreen" n4.editorial.color = "purple" else: n3.editorial.ficta = pitch.Accidental("sharp") n3.editorial.misc["capua-ficta"] = pitch.Accidental("sharp") n1.editorial.color = "purple" n2.editorial.color = "purple" n3.editorial.color = "ForestGreen" n4.editorial.color = "purple" return numChanged
def fix(self): for (midiRef, omrRef, op) in self.changes: omrRef.color = "black" # if they're not notes, don't bother with rest if self.checkIfNoteInstance(midiRef, omrRef) is False: continue # if the are the same, don't bother to try changing it # 3 is the number of noChange Ops if isinstance(op, aligner.ChangeOps) and op == aligner.ChangeOps.NoChange: continue # don't bother with notes with too big of an interval between them if self.intervalTooBig(midiRef, omrRef, setint=5): continue # case 1: omr has extraneous natural sign in front of it, get rid of it if self.hasNatAcc(omrRef): if self.isEnharmonic(midiRef, omrRef): omrRef.pitch.accidental = None else: # case 2-1: midi note is sharp, omr note is one step higher and natural, # should be a flat instead. e.g midi = g#, gt = a-, omr = an # omr note has higher ps than midi-- on a higher # line or space than midi note if omrRef.pitch > midiRef.pitch: if omrRef.pitch.transpose(interval.Interval(-1) ).isEnharmonic(midiRef.pitch): omrRef.pitch.accidental = pitch.Accidental('flat') # case 2-2: midi note is flat, omr note is one step lower and natural, # should be a flat instead. e.g midi = g-, gt = f#, omr = fn # omr note has lower ps than midi-- on a higher line # or space than midi note elif omrRef.pitch < midiRef.pitch: if omrRef.pitch.transpose(interval.Interval(1) ).isEnharmonic(midiRef.pitch): omrRef.pitch.accidental = pitch.Accidental('sharp') # case 3: notes are on same step, but omr got read wrong. # e.g. midi = g#, gt = g#, omr = gn or omr = g- elif self.hasSharpFlatAcc(omrRef) and self.stepEq(midiRef, omrRef): if self.hasAcc(omrRef): omrRef.pitch.accidental = midiRef.pitch.accidental else: omrRef.pitch.accidental = None elif self.hasSharpFlatAcc(omrRef) and self.stepNotEq(midiRef, omrRef): # case 4-1: notes are on different step, off by an interval of 2, # omr note is higher and sharp # e.g. midi = g#, gt = a-, omr = a# if omrRef.pitch > midiRef.pitch: if omrRef.pitch.accidental == pitch.Accidental('sharp'): if omrRef.pitch.transpose(interval.Interval(-2) ).isEnharmonic(midiRef.pitch): omrRef.pitch.accidental = pitch.Accidental('flat') # case 4-2: notes are on different step, off by an interval of 2, # omr note is lower and flat # e.g. midi = a-, gt = g#, omr = g- elif omrRef.pitch < midiRef.pitch: if omrRef.pitch.accidental == pitch.Accidental('flat'): if omrRef.pitch.transpose(interval.Interval(2) ).isEnharmonic(midiRef.pitch): omrRef.pitch.accidental = pitch.Accidental('sharp') # case 5: same step, MIDI has accidental, # omr was read wrong (e.g. key signature not parsed) # e.g. midi = b-, gt = b-, omr= elif (omrRef.pitch != midiRef.pitch and self.hasSharpFlatAcc(midiRef) and self.stepEq(midiRef, omrRef)): omrRef.pitch = midiRef.pitch
def capuaRuleTwo(srcStream): ''' See capuaRuleOne for precise instructions. Applies Capua's second rule to the given srcStream, i.e. if four notes are ascending with the pattern M2 m2 M2, the intervals shall be made M2 M2 m2. Also changes note.style.color for rule 2 (purple purple green purple). returns the number of times any note was changed ''' numChanged = 0 ssn = srcStream.flat.notesAndRests for i in range(len(ssn) - 3): n1 = ssn[i] n2 = ssn[i + 1] n3 = ssn[i + 2] n4 = ssn[i + 3] if (n1.isRest or n2.isRest or n3.isRest or n4.isRest): continue i1 = interval.notesToInterval(n1, n2) i2 = interval.notesToInterval(n2, n3) i3 = interval.notesToInterval(n3, n4) if (n1.pitch.accidental is not None or n2.pitch.accidental is not None or n4.pitch.accidental is not None): continue # never seems to improve things... if n3.step == 'A' or n3.step == 'D': continue # e.g., D E F G => D E F# G # or F A Bb C => F A B C if (i1.directedName == 'M2' and i2.directedName == 'm2' and i3.directedName == 'M2'): numChanged += 1 if 'capuaRuleNumber' in n3.editorial: n3.editorial.capuaRuleNumber += RULE_TWO else: n3.editorial.capuaRuleNumber = RULE_TWO if n3.pitch.accidental is not None and n3.pitch.accidental.name == 'flat': n3.editorial.savedAccidental = n3.pitch.accidental n3.pitch.accidental = None n3.editorial.ficta = pitch.Accidental('natural') n3.editorial.capuaFicta = pitch.Accidental('natural') n1.style.color = 'purple' n2.style.color = 'purple' n3.style.color = 'ForestGreen' n4.style.color = 'purple' else: n3.editorial.ficta = pitch.Accidental('sharp') n3.editorial.capuaFicta = pitch.Accidental('sharp') n1.style.color = 'purple' n2.style.color = 'purple' n3.style.color = 'ForestGreen' n4.style.color = 'purple' return numChanged