def findPotentialPassingTones(show=True): g = corpus.parse("gloria") gcn = g.parts["cantus"].measures(1, 126).flat.notesAndRests gcn[0].lyric = "" gcn[-1].lyric = "" for i in range(1, len(gcn) - 1): prev = gcn[i - 1] cur = gcn[i] next = gcn[i + 1] # @ReservedAssignment cur.lyric = "" if "Rest" in prev.classes or "Rest" in cur.classes or "Rest" in next.classes: continue int1 = interval.notesToInterval(prev, cur) if int1.isStep is False: continue int2 = interval.notesToInterval(cur, next) if int2.isStep is False: continue cma = cur.beatStrength if cma < 1 and cma <= prev.beatStrength and cma <= next.beatStrength: if int1.direction == int2.direction: cur.lyric = "pt" # neighbor tone else: cur.lyric = "nt" # passing tone if show: g.parts["cantus"].show()
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 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 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 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.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 ("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.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 = "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 findPotentialPassingTones(show=True): g = corpus.parse('gloria') gcn = g.parts['cantus'].measures(1, 126).flat.notesAndRests gcn[0].lyric = "" gcn[-1].lyric = "" for i in range(1, len(gcn) - 1): prev = gcn[i - 1] cur = gcn[i] nextN = gcn[i + 1] cur.lyric = "" if ("Rest" in prev.classes or "Rest" in cur.classes or "Rest" in nextN.classes): continue int1 = interval.notesToInterval(prev, cur) if int1.isStep is False: continue int2 = interval.notesToInterval(cur, nextN) if int2.isStep is False: continue cma = cur.beatStrength if (cma < 1 and cma <= prev.beatStrength and cma <= nextN.beatStrength): if int1.direction == int2.direction: cur.lyric = 'pt' # neighbor tone else: cur.lyric = 'nt' # passing tone if show: g.parts['cantus'].show()
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.style.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(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.style.color = "blue" n2.style.color = "forestGreen" n3.style.color = "blue" else: n2.editorial.ficta = pitch.Accidental("sharp") n2.editorial.misc["capua-ficta"] = pitch.Accidental("sharp") n1.style.color = "blue" n2.style.color = "ForestGreen" n3.style.color = "blue" return numChanged
def isParallelUnison(self, note11, note12, note21, note22): '''Given four notes, assuming the first pair sounds at the same time and the second pair sounds at the same time, returns True if the two harmonic intervals are P8 and False otherwise.''' interval1 = interval.notesToInterval(note11, note21) interval2 = interval.notesToInterval(note12, note22) if interval1.name == interval2.name == "P1": return True else: return False
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 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 under "saved-accidental" and changes note.editorial.color for rule 1 (blue green blue). Returns the number of changes. ''' numChanged = 0 ssn = srcStream.notes 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 = notesToInterval(n1,n2) i2 = 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. 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.accidental is not None and n2.accidental.name == "flat"): n2.editorial.misc["saved-accidental"] = n2.accidental n2.accidental = None n2.editorial.ficta = Accidental("natural") n2.editorial.misc["capua-ficta"] = Accidental("natural") n1.editorial.color = "blue" n2.editorial.color = "forestGreen" n3.editorial.color = "blue" else: n2.editorial.ficta = Accidental("sharp") n2.editorial.misc["capua-ficta"] = Accidental("sharp") n1.editorial.color = "blue" n2.editorial.color = "ForestGreen" n3.editorial.color = "blue" 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 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.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 ("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 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.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 ("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 searchForIntervals(notesStr): ''' notesStr is the same as above. Now however we check to see if the generic intervals are the same, rather than the note names. Useful if the clef is missing. ''' notesArr = notesStr.split() noteObjArr = [] for tN in notesArr: tNObj = note.Note() tNObj.name = tN[0] tNObj.octave = int(tN[1]) noteObjArr.append(tNObj) interObjArr = [] for i in range(len(noteObjArr) - 1): int1 = interval.notesToInterval(noteObjArr[i], noteObjArr[i + 1]) interObjArr.append(int1) #print interObjArr searcher1 = IntervalSearcher(interObjArr) ballataObj = cadencebook.BallataSheet() streamOpus = stream.Opus() for thisWork in ballataObj: print(thisWork.title) for thisCadence in thisWork.snippets: if thisCadence is None: continue for i in range(len(thisCadence.parts)): colorFound(searcher1, thisCadence, streamOpus, thisWork, i) if any(streamOpus): streamOpus.show('lily.png')
def getDominant(self): interval1to5 = interval.notesToInterval(self.tonic, self.pitchFromScaleDegree(5)) if interval1to5.specificName != "Perfect": print(interval1to5.diatonicType) raise ScaleException("This scale has no Dominant (Locrian perhaps?)") else: return self.pitchFromScaleDegree(5)
def resolves(voice, resolve_interval): """Given a voice starting with the note that must resolve, checks whether it resolves according to the provided resolveInterval integer >>> from music21 import note, stream >>> voice = stream.Part() >>> for current_note in map(note.Note, ['f4', 'e4', 'f4']): ... voice.append(current_note) >>> resolves(voice, -2) True >>> resolves(voice, 2) False """ if len(voice) < 2: return True first_note = voice[0] for note in voice[1:]: current_interval = interval.notesToInterval(first_note, note) if current_interval.generic.directed == resolve_interval: return True # returns false if the resolve interval is wrong or there a chromatic step in the wrong direction if current_interval.generic.directed != 1 or resolve_interval * current_interval.chromatic.directed < 0: return return True
def transposed_to( self, pitch: Pitch = Pitch()) -> Tuple['SpotifyChord', Optional[Interval]]: if self.is_no_chord(): return self, None tr_int = interval.notesToInterval(self.root, pitch) return self.transposed_by(tr_int), tr_int
def generateFirstSpecies(self, stream1, minorScale): '''Given a stream (the cantus firmus) and the stream's key in the form of a MinorScale object, generates a stream of first species counterpoint that follows the rules of 21M.301.''' # DOES NOT YET CHECK FOR TOO MANY THIRDS/SIXTHS IN A ROW, # DOES NOT YET RAISE LEADING TONES, AND DOES NOT CHECK FOR NOODLING. stream2 = Stream([]) firstNote = stream1.notes[0] choices = [interval.transposeNote(firstNote, "P1"),\ interval.transposeNote(firstNote, "P5"),\ interval.transposeNote(firstNote, "P8")] note1 = random.choice(choices) note1.duration = firstNote.duration stream2.append(note1) afterLeap = False for i in range(1, len(stream1.notes)): prevFirmus = stream1.notes[i-1] currFirmus = stream1.notes[i] prevNote = stream2.notes[i-1] choices = self.generateValidNotes(prevFirmus, currFirmus, prevNote, afterLeap, minorScale) if len(choices) == 0: raise ModalCounterpointException("Sorry, please try again") newNote = random.choice(choices) newNote.duration = currFirmus.duration stream2.append(newNote) int = interval.notesToInterval(prevNote, newNote) if int.generic.undirected > 3: afterLeap = True else: afterLeap = False return stream2
def isHiddenFifth(self, note11, note12, note21, note22): '''Given four notes, assuming the first pair sounds at the same time and the second pair sounds at the same time, returns True if there is a hidden fifth and false otherwise.''' interval1 = interval.notesToInterval(note11, note21) interval2 = interval.notesToInterval(note12, note22) interval3 = interval.notesToInterval(note11, note12) interval4 = interval.notesToInterval(note21, note22) if interval3.direction > 0 and interval4.direction > 0: if interval2.name == "P5" and not interval1.name == "P5": return True else: return False elif interval3.direction < 0 and interval4.direction < 0: if interval2.name == "P5" and not interval1.name == "P5": return True else: return False elif interval3.direction == interval4.direction == 0: return False return False
def generateTripletBlues(blRealization=None, numRepeats=5): # 12/8 ''' Turns whole notes in twelve bar blues bass line to triplet blues bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1, 4), (2, 12), (3, 12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateTripletBlues(numRepeats=1).show() .. image:: images/figuredBass/fbExamples_tripletBlues.* :width: 700 ''' from music21 import converter from music21 import stream from music21 import interval from music21 import meter if blRealization is None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) tripletBassLine = converter.parse( "tinynotation: BB-4 BB-8 D4 D8 F4 F8 A-8 G8 F8", makeNotation=False) newBassLine = stream.Part() for n in sampleScore[1].notes: i = interval.notesToInterval(tripletBassLine[0], n) tp = tripletBassLine.transpose(i) for lyr in n.lyrics: tp.notes.first().addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newTopLine = stream.Part() for sampleChord in sampleScore[0].notes: sampleChordCopy = copy.deepcopy(sampleChord) sampleChordCopy.quarterLength = 6.0 newTopLine.append(sampleChordCopy) newScore = stream.Score() newScore.append(meter.TimeSignature("12/8")) # Time signature newScore.append(sampleScore[1][1]) # Key signature newScore.insert(0, newTopLine) newScore.insert(0, newBassLine) return newScore
def countMelodicIntervals(self, sStream, found=None, ignoreDirection=True, ignoreUnison=True): ''' Find all unique melodic intervals in this Stream. If `found` is provided as a dictionary, this dictionary will be used to store Intervals, and counts of Intervals already found will be incremented. ''' # note that Stream.findConsecutiveNotes() and Stream.melodicIntervals() # offer similar approaches, but return Streams and manage offsets and durations, components not needed here if found == None: found = {} # if this has parts, need to move through each at a time if sStream.hasPartLikeStreams(): procList = [s for s in sStream.getElementsByClass('Stream')] else: # assume a single list of notes procList = [sStream] for p in procList: # get only Notes for now, skipping rests and chords noteStream = p.stripTies(inPlace=False).getElementsByClass('Note') #noteStream.show() for i, n in enumerate(noteStream): if i <= len(noteStream) - 2: nNext = noteStream[i+1] else: nNext = None if nNext is not None: #environLocal.printDebug(['creating interval from notes:', n, nNext, i]) i = interval.notesToInterval(n, nNext) if ignoreUnison: # will apply to enharmonic eq unisons if i.chromatic.semitones == 0: continue if ignoreDirection: if i.chromatic.semitones < 0: i = i.reverse() # must use directed name for cases where ignoreDirection # is false if i.directedName not in found.keys(): found[i.directedName] = [i, 1] else: found[i.directedName][1] += 1 # increment counter # def compare(x, y): # return abs(x.chromatic.semitones) - abs(y.chromatic.semitones) # found.sort(cmp=compare) return found
def findPotentialPassingTones(show=True): g = corpus.parse('gloria') gcn = g.parts['cantus'].measures(1,126).flat.notesAndRests gcn[0].lyric = "" gcn[-1].lyric = "" for i in range(1, len(gcn) - 1): prev = gcn[i-1] cur = gcn[i] nextN = gcn[i+1] cur.lyric = "" if ("Rest" in prev.classes or "Rest" in cur.classes or "Rest" in nextN.classes): continue int1 = interval.notesToInterval(prev, cur) if int1.isStep is False: continue int2 = interval.notesToInterval(cur, nextN) if int2.isStep is False: continue cma = cur.beatStrength if (cma < 1 and cma <= prev.beatStrength and cma <= nextN.beatStrength): if int1.direction == int2.direction: cur.lyric = 'pt' # neighbor tone else: cur.lyric = 'nt' # passing tone if show: g.parts['cantus'].show()
def searchForIntervals(notesStr): ''' notesStr is the same as above. Now however we check to see if the generic intervals are the same, rather than the note names. Useful if the clef is missing. ''' notesArr = notesStr.split() noteObjArr = [] for tN in notesArr: tNObj = note.Note() tNObj.name = tN[0] tNObj.octave = int(tN[1]) noteObjArr.append(tNObj) interObjArr = [] for i in range(len(noteObjArr) - 1): int1 = interval.notesToInterval(noteObjArr[i], noteObjArr[i + 1]) interObjArr.append(int1) #print interObjArr searcher1 = IntervalSearcher(interObjArr) ballataObj = cadencebook.BallataSheet() streamOpus = stream.Opus() for thisWork in ballataObj: print(thisWork.title) for thisCadence in thisWork.snippets: if thisCadence is None: continue for i in range(len(thisCadence.parts)): if searcher1.compareToStream( thisCadence.parts[i].flat) is True: notesStr = "" for thisNote in thisCadence.parts[i].flat.notesAndRests: #thisNote.editorial.color = "blue" if thisNote.isRest is False: notesStr += thisNote.nameWithOctave + " " else: notesStr += "r " streamOpus.insert(0, thisCadence) # streamLily += "\\score {" + \ # "<< \\time " + str(thisCadence.timeSig) + \ # "\n \\new Staff {" + str(thisCadence.parts[i].lily) + "} >>" + \ # thisCadence.header() + "\n}\n" print(u"In piece %r found in stream %d: %s" % (thisWork.title, i, notesStr)) if len(streamOpus) > 0: streamOpus.show('lily.png')
def ch1_writing_II_A(show=True, *arguments, **keywords): '''p. 7 Compose a melody using whole and half steps in any musical style. This technique uses a random walk of whole or half steps with direction choices determined by whether the present note is above or below the target end. ''' import random from music21 import stream, expressions, pitch dirWeight = [-1, 1] # start with an even distribution s = stream.Stream() nStart = note.Note('g4') n = copy.deepcopy(nStart) while True: # n.quarterLength = random.choice([.25, .5, 1]) n.duration.type = random.choice(['16th', 'eighth', 'quarter']) s.append(n) # if we have written more than fifteen notes # and the last notes matches the first pitch class, then end. if len(s) > 4 and n.pitch.pitchClass == nStart.pitch.pitchClass: n.expressions.append(expressions.Fermata()) break if len(s) > 30: # emergency break in case the piece is too long break direction = random.choice(dirWeight) if direction == 1: i = random.choice(['w', 'h']) else: i = random.choice(['w-', 'h-']) try: n = n.transpose(i) except pitch.AccidentalException: break # end b/c our transposition have exceeded accidental range iSpread = interval.notesToInterval(nStart, n) if iSpread.direction == -1: # we are below our target, favor upward dirWeight = [-1, 1, 1] if iSpread.direction == 1: # we are above our target, favor down dirWeight = [-1, -1, 1] if show: s.show() else: unused_post = musicxml.m21ToString.fromMusic21Object(s)
def generateTripletBlues(blRealization=None, numRepeats=5): # 12/8 """ Turns whole notes in twelve bar blues bass line to triplet blues bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1,4),(2,12),(3,12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateTripletBlues(numRepeats = 1).show() .. image:: images/figuredBass/fbExamples_tripletBlues.* :width: 700 """ from music21 import tinyNotation, stream, interval, meter if blRealization == None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) tripletBassLine = tinyNotation.TinyNotationStream("BB-4 BB-8 D4 D8 F4 F8 A-8 G8 F8") newBassLine = stream.Part() for n in sampleScore[1].notes: i = interval.notesToInterval(tripletBassLine[0], n) tp = tripletBassLine.transpose(i) for lyr in n.lyrics: tp.notes[0].addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newTopLine = stream.Part() for sampleChord in sampleScore[0].notes: sampleChordCopy = copy.deepcopy(sampleChord) sampleChordCopy.quarterLength = 6.0 newTopLine.append(sampleChordCopy) newScore = stream.Score() newScore.append(meter.TimeSignature("12/8")) # Time signature newScore.append(sampleScore[1][1]) # Key signature newScore.insert(0, newTopLine) newScore.insert(0, newBassLine) return newScore
def searchForIntervals(notesStr): ''' notesStr is the same as above. Now however we check to see if the generic intervals are the same, rather than the note names. Useful if the clef is missing. ''' notesArr = notesStr.split() noteObjArr = [] for tN in notesArr: tNObj = note.Note() tNObj.name = tN[0] tNObj.octave = int(tN[1]) noteObjArr.append(tNObj) interObjArr = [] for i in range(len(noteObjArr) - 1): int1 = interval.notesToInterval(noteObjArr[i], noteObjArr[i+1]) interObjArr.append(int1) #print interObjArr searcher1 = IntervalSearcher(interObjArr) ballataObj = cadencebook.BallataSheet() streamOpus = stream.Opus() for thisWork in ballataObj: print(thisWork.title) for thisCadence in thisWork.snippets: if thisCadence is None: continue for i in range(len(thisCadence.parts)): if searcher1.compareToStream(thisCadence.parts[i].flat) is True: notesStr = "" for thisNote in thisCadence.parts[i].flat.notesAndRests: #thisNote.editorial.color = "blue" if thisNote.isRest is False: notesStr += thisNote.nameWithOctave + " " else: notesStr += "r " streamOpus.insert(0, thisCadence) # streamLily += "\\score {" + \ # "<< \\time " + str(thisCadence.timeSig) + \ # "\n \\new Staff {" + str(thisCadence.parts[i].lily) + "} >>" + \ # thisCadence.header() + "\n}\n" print(u"In piece %r found in stream %d: %s" % (thisWork.title, i, notesStr)) if len(streamOpus) > 0: streamOpus.show('lily.png')
def corpusFindMelodicSevenths(show=True): # find and display melodic sevenths import os from music21.analysis import discrete mid = discrete.MelodicIntervalDiversity() groupEast = corpus.search('shanxi', field='locale') groupWest = corpus.search('niederlande', field='locale') found = [] for unused_name, group in [('shanxi', groupEast), ('niederlande', groupWest)]: for fp, n in group: s = converter.parse(fp, number=n) intervalDict = mid.countMelodicIntervals(s) for key in sorted(intervalDict.keys()): if key in ['m7', 'M7']: found.append([fp, n, s]) results = stream.Stream() for fp, num, s in found: environLocal.printDebug(['working with found', fp, num]) # this assumes these are all monophonic noteStream = s.flat.getElementsByClass('Note') for i, n in enumerate(noteStream): if i <= len(noteStream) - 2: nNext = noteStream[i + 1] else: nNext = None if nNext is not None: #environLocal.printDebug(['creating interval from notes:', n, nNext, i]) i = interval.notesToInterval(n, nNext) environLocal.printDebug(['got interval', i.name]) if i.name in ['m7', 'M7']: #n.addLyric(s.metadata.title) junk, fn = os.path.split(fp) n.addLyric('%s: %s' % (fn, num)) m = noteStream.extractContext( n, 1, 2, forceOutputClass=stream.Measure) m.makeAccidentals() m.timeSignature = m.bestTimeSignature() results.append(m) if show == True: results.show()
def ch1_basic_I_B(show=True, *arguments, **keywords): """ p2. given 2 pitches, mark on a keyboard their positions and mark intervals as W for whole step and H for half step, otherwise N """ pitches = [("a#", "b"), ("b-", "c#"), ("g-", "a"), ("d-", "c##"), ("f", "e"), ("f#", "e")] for i, j in pitches: n1 = note.Note(i) n2 = note.Note(j) i1 = interval.notesToInterval(n1, n2) if i1.intervalClass == 1: # by interval class unused_mark = "H" elif i1.intervalClass == 2: unused_mark = "W" else: unused_mark = "N"
def generateBoogieVamp(blRealization=None, numRepeats=5): ''' Turns whole notes in twelve bar blues bass line to blues boogie woogie bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1, 4), (2, 12), (3, 12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateBoogieVamp(numRepeats=1).show() .. image:: images/figuredBass/fbExamples_boogieVamp.* :width: 700 ''' from music21 import converter from music21 import stream from music21 import interval if blRealization is None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) boogieBassLine = converter.parse( "tinynotation: BB-8. D16 F8. G16 A-8. G16 F8. D16", makeNotation=False) newBassLine = stream.Part() newBassLine.append(sampleScore[1][0]) # Time signature newBassLine.append(sampleScore[1][1]) # Key signature for n in sampleScore[1].notes: i = interval.notesToInterval(boogieBassLine[0], n) tp = boogieBassLine.transpose(i) for lyr in n.lyrics: tp.notes.first().addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newScore = stream.Score() newScore.insert(0, sampleScore[0]) newScore.insert(newBassLine) return newScore
def corpusFindMelodicSevenths(show = True): # find and display melodic sevenths import os from music21.analysis import discrete mid = discrete.MelodicIntervalDiversity() groupEast = corpus.search('shanxi', field='locale') groupWest = corpus.search('niederlande', field='locale') found = [] for unused_name, group in [('shanxi', groupEast), ('niederlande', groupWest)]: for fp, n in group: s = converter.parse(fp, number=n) intervalDict = mid.countMelodicIntervals(s) for key in sorted(intervalDict.keys()): if key in ['m7', 'M7']: found.append([fp, n, s]) results = stream.Stream() for fp, num, s in found: environLocal.printDebug(['working with found', fp, num]) # this assumes these are all monophonic noteStream = s.flat.getElementsByClass('Note') for i, n in enumerate(noteStream): if i <= len(noteStream) - 2: nNext = noteStream[i+1] else: nNext = None if nNext is not None: #environLocal.printDebug(['creating interval from notes:', n, nNext, i]) i = interval.notesToInterval(n, nNext) environLocal.printDebug(['got interval', i.name]) if i.name in ['m7', 'M7']: #n.addLyric(s.metadata.title) junk, fn = os.path.split(fp) n.addLyric('%s: %s' % (fn, num)) m = noteStream.extractContext(n, 1, 2, forceOutputClass=stream.Measure) m.makeAccidentals() m.timeSignature = m.bestTimeSignature() results.append(m) if show == True: results.show()
def ch1_basic_I_B(show=True, *arguments, **keywords): ''' p2. given 2 pitches, mark on a keyboard their positions and mark intervals as W for whole step and H for half step, otherwise N ''' pitches = [('a#', 'b'), ('b-', 'c#'), ('g-', 'a'), ('d-', 'c##'), ('f', 'e'), ('f#', 'e')] for i,j in pitches: n1 = note.Note(i) n2 = note.Note(j) i1 = interval.notesToInterval(n1, n2) if i1.intervalClass == 1: # by interval class unused_mark = "H" elif i1.intervalClass == 2: unused_mark = "W" else: unused_mark = "N"
def generateBoogieVamp(blRealization=None, numRepeats=5): """ Turns whole notes in twelve bar blues bass line to blues boogie woogie bass line. Takes in numRepeats, which is the number of times to repeat the bass line. Also, takes in a realization of :meth:`~music21.figuredBass.examples.twelveBarBlues`. If none is provided, a default realization with :attr:`~music21.figuredBass.rules.Rules.forbidVoiceOverlap` set to False and :attr:`~music21.figuredBass.rules.Rules.partMovementLimits` set to [(1,4),(2,12),(3,12)] is used. >>> from music21.figuredBass import examples >>> #_DOCS_SHOW examples.generateBoogieVamp(numRepeats = 1).show() .. image:: images/figuredBass/fbExamples_boogieVamp.* :width: 700 """ from music21 import tinyNotation, stream, interval if blRealization == None: bluesLine = twelveBarBlues() fbRules = rules.Rules() fbRules.partMovementLimits = [(1, 4), (2, 12), (3, 12)] fbRules.forbidVoiceOverlap = False blRealization = bluesLine.realize(fbRules) sampleScore = blRealization.generateRandomRealizations(numRepeats) boogieBassLine = tinyNotation.TinyNotationStream("BB-8. D16 F8. G16 A-8. G16 F8. D16") newBassLine = stream.Part() newBassLine.append(sampleScore[1][0]) # Time signature newBassLine.append(sampleScore[1][1]) # Key signature for n in sampleScore[1].notes: i = interval.notesToInterval(boogieBassLine[0], n) tp = boogieBassLine.transpose(i) for lyr in n.lyrics: tp.notes[0].addLyric(lyr.text) for m in tp.notes: newBassLine.append(m) newScore = stream.Score() newScore.insert(0, sampleScore[0]) newScore.insert(newBassLine) return newScore
def construct_music21(musicobject): """Export a music21 stream from the given musicobject.""" if type(musicobject) == Tone: if isinstance(musicobject.frequency, float): n = note.Note() difference = frequency_to_semitone(musicobject.frequency) n.transpose(difference, inPlace=True) elif musicobject.frequency == '_': n = note.Rest() else: n = note.Note() n.pitch.name = musicobject.frequency n.duration.quarterLength = musicobject.duration return n if type(musicobject) == Group: compound = stream.Stream() for sequence in musicobject.sequences: s = stream.Stream() for element in sequence: s.append(construct_music21(element)) compound.insert(0, s) return compound.flat if type(musicobject) == Transformed: subject = construct_music21(musicobject.subject) T = musicobject.transformation # Apply duration transformation if type(musicobject.subject) == Tone: subject.duration = duration.Duration(subject.duration.quarterLength * T.duration) else: subject.scaleDurations(T.duration) subject.scaleOffsets(T.duration) # Apply frequency transformation if isinstance(T.frequency, float): difference = frequency_to_semitone(T.frequency) else: difference = interval.notesToInterval(note.Note('c4'), note.Note(T.frequency)) subject.transpose(difference, inPlace=True) return subject
def searchForIntervals(notesStr): '''notesStr is the same as above. Now however we check to see if the generic intervals are the same, rather than the note names. Useful if the clef is missing. ''' notesArr = notesStr.split() noteObjArr = [] for tN in notesArr: tNObj = Note() tNObj.name = tN[0] tNObj.octave = int(tN[1]) noteObjArr.append(tNObj) interObjArr = [] for i in range(len(noteObjArr) - 1): int1 = interval.notesToInterval(noteObjArr[i], noteObjArr[i+1]) interObjArr.append(int1) #print interObjArr searcher1 = IntervalSearcher(interObjArr) ballataObj = cadencebook.BallataSheet() streamLily = "" for thisWork in ballataObj: for thisCadence in thisWork.snippets: if (thisCadence is None): continue for i in range(len(thisCadence.parts)): if searcher1.compareToStream(thisCadence.parts[i].flat) is True: notesList = "" for thisNote in thisCadence.parts[i].flat.notes: notesList += thisNote.name + " " #thisNote.editorial.color = "blue" streamLily += "\\score {" + \ "<< \\time " + str(thisCadence.timeSig) + \ "\n \\new Staff {" + str(thisCadence.parts[i].lily) + "} >>" + \ str(thisCadence.header()) + "\n}\n" print("In piece %r found in stream %d: %s" % (thisWork.title, i, notesList)) if streamLily: print(streamLily) lily.lilyString.LilyString(streamLily).showPDF()
def check_augmented_seconds(voice): """Raises an error if the interval between two notes in a voice is an augmented second. >>> from music21 import note, stream >>> soprano = stream.Part(map(note.Note, ['D5', 'E-5', 'F#5'])) >>> bass = stream.Part(map(note.Note, ['B-2', 'G2', 'A2'])) >>> check_augmented_seconds(soprano) Traceback (most recent call last): ... errors.AugmentedSecondError: Found augmented second at index 2 >>> check_augmented_seconds(bass) """ previous_note = None for i, current_note in enumerate(voice): if i > 0: test_interval = interval.notesToInterval(previous_note, current_note) if test_interval.name == "A2": raise AugmentedSecondError(i) previous_note = current_note
def base40ActualInterval(base40NumA, base40NumB): ''' Calculates a music21 Interval between two Base40 pitch numbers, as calculated using the music21.interval module. Raises a Base40 Exception if (a) Either of the Base40 pitch numbers does not correspond to a pitch name or (b) If an unusual interval is encountered that can't be handled by music21. >>> musedata.base40.base40ActualInterval(163, 191) <music21.interval.Interval m6> >>> musedata.base40.base40ActualInterval(186, 174) #Descending M3 <music21.interval.Interval M-3> >>> musedata.base40.base40ActualInterval(1, 5) <music21.interval.Interval AAAA1> >>> musedata.base40.base40ActualInterval(1, 3) <music21.interval.Interval AA1> >>> musedata.base40.base40ActualInterval(2, 6) Traceback (most recent call last): music21.musedata.base40.Base40Exception: Pitch name not assigned to this Base40 number 6 OMIT_FROM_DOCS >>> musedata.base40.base40ActualInterval(12, 6) Traceback (most recent call last): music21.musedata.base40.Base40Exception: Pitch name not assigned to this Base40 number 12 ''' pitchA = base40ToPitch(base40NumA) pitchB = base40ToPitch(base40NumB) noteA = note.Note() noteA.pitch = pitchA noteB = note.Note() noteB.pitch = pitchB try: return interval.notesToInterval(noteA, noteB) except IndexError: raise Base40Exception( 'Unusual interval- Limitation of music21.interval')
def iqRootsAndPercentage(analysisStream): totalDuration = analysisStream.duration.quarterLength romMerged = analysisStream.flat.stripTies() major = "" minor = "" active = 'minor' for element in romMerged: if "RomanNumeral" in element.classes: #distanceToTonicInSemis = int((element.root().ps - # pitch.Pitch(element.scale.tonic).ps) % 12) elementLetter = str(element.root().name) ## leave El if element.quality == 'minor' or element.quality == 'diminished': elementLetter = elementLetter.lower() elif element.quality == 'other': rootScaleDegree = element.scale.getScaleDegreeFromPitch( element.root()) if rootScaleDegree: thirdPitch = element.scale.pitchFromDegree( (rootScaleDegree + 2) % 7) int1 = interval.notesToInterval(element.root(), thirdPitch) if int1.intervalClass == 3: elementLetter = elementLetter.lower() else: pass longString = elementLetter + " (" + str( int(element.duration.quarterLength * 10000 / totalDuration) / 100) + ") " if active == 'major': major += longString else: minor += longString elif "Key" in element.classes: if element.mode == 'major': active = 'major' major += "\n" + element.tonic + " " + element.mode + " " else: active = 'minor' minor += "\n" + element.tonic + " " + element.mode + " " return (major, minor)
def base40ActualInterval(base40NumA, base40NumB): ''' Calculates a music21 Interval between two Base40 pitch numbers, as calculated using the music21.interval module. Raises a Base40 Exception if (a) Either of the Base40 pitch numbers does not correspond to a pitch name or (b) If an unusual interval is encountered that can't be handled by music21. >>> from music21 import * >>> base40ActualInterval(163,191) <music21.interval.Interval m6> >>> base40ActualInterval(186,174) #Descending M3 <music21.interval.Interval M-3> >>> base40ActualInterval(1,5) <music21.interval.Interval AAAA1> >>> base40ActualInterval(1,3) <music21.interval.Interval AA1> >>> base40ActualInterval(2,6) Traceback (most recent call last): Base40Exception: Pitch name not assigned to this Base40 number 6 OMIT_FROM_DOCS >>> base40ActualInterval(12,6) Traceback (most recent call last): Base40Exception: Pitch name not assigned to this Base40 number 12 ''' pitchA = base40ToPitch(base40NumA) pitchB = base40ToPitch(base40NumB) noteA = note.Note() noteA.pitch = pitchA noteB = note.Note() noteB.pitch = pitchB try: return interval.notesToInterval(noteA,noteB) except IndexError: raise Base40Exception('Unusual interval- Limitation of music21.interval')
def iqRootsAndPercentage(analysisStream): totalDuration = analysisStream.duration.quarterLength romMerged = analysisStream.flat.stripTies() major = "" minor = "" active = 'minor' for element in romMerged: if "RomanNumeral" in element.classes: #distanceToTonicInSemis = int((element.root().ps - # pitch.Pitch(element.scale.tonic).ps) % 12) elementLetter = str(element.root().name) ## leave El if element.quality == 'minor' or element.quality == 'diminished': elementLetter = elementLetter.lower() elif element.quality == 'other': rootScaleDegree = element.scale.getScaleDegreeFromPitch(element.root()) if rootScaleDegree: thirdPitch = element.scale.pitchFromDegree((rootScaleDegree + 2) % 7) int1 = interval.notesToInterval(element.root(), thirdPitch) if int1.intervalClass == 3: elementLetter = elementLetter.lower() else: pass longString = elementLetter + " (" + str(int( element.duration.quarterLength * 10000 / totalDuration) / 100) + ") " if active == 'major': major += longString else: minor += longString elif "Key" in element.classes: if element.mode == 'major': active = 'major' major += "\n" + element.tonic + " " + element.mode + " " else: active = 'minor' minor += "\n" + element.tonic + " " + element.mode + " " return (major, minor)
def isValidStep(self, note11, note12): '''Determines if the melodic interval between two given notes is "legal" according to 21M.301 rules of counterpoint.''' interval1 = interval.notesToInterval(note11, note12) if interval1.diatonic.name in self.legalMelodicIntervals: return True else: return False
def generateValidNotes(self, prevFirmus, currFirmus, prevNote, afterLeap, minorScale): '''Helper function for generateFirstSpecies; gets a list of possible next notes based on valid melodic intervals, then checks each one so that parallel/hidden fifths/octaves, voice crossing, and invalid harmonies are prevented. Adds extra weight to notes that would create contrary motion.''' print currFirmus.name valid = [] bottomInt = interval.notesToInterval(prevFirmus, currFirmus) if bottomInt.direction < 0: ascending = True else: ascending = False n1 = interval.transposeNote(prevNote, "m2") n2 = interval.transposeNote(prevNote, "M2") n3 = interval.transposeNote(prevNote, "m3") n4 = interval.transposeNote(prevNote, "M3") n5 = interval.transposeNote(prevNote, "P4") n6 = interval.transposeNote(prevNote, "P5") if afterLeap: possible = [n1, n2, n3, n4] else: possible = [n1, n2, n3, n4, n5, n6] possible.extend(possible) n7 = interval.transposeNote(prevNote, "m-2") n8 = interval.transposeNote(prevNote, "M-2") n9 = interval.transposeNote(prevNote, "m-3") n10 = interval.transposeNote(prevNote, "M-3") n11 = interval.transposeNote(prevNote, "P-4") n12 = interval.transposeNote(prevNote, "P-5") if afterLeap: possible.extend([n7, n8, n9, n10]) else: possible.extend([n7, n8, n9, n10, n11, n12]) print "possible: ", [note1.name for note1 in possible] for note1 in possible: try: validHarmony = self.isValidHarmony(note1, currFirmus) except: validHarmony = False # vlq = VoiceLeadingQuartet(prevNote, prevFirmus, note1, currFirmus) # par5 = vlq.parallelFifth() # par8 = vlq.parallelOctave() # hid5 = vlq.hiddenFifth() # hid8 = vlq.hiddenOctave() # par1 = vlq.parallelUnison() try: par5 = self.isParallelFifth(prevNote, note1, prevFirmus, currFirmus) except: par5 = True try: par8 = self.isParallelOctave(prevNote, note1, prevFirmus, currFirmus) except: par8 = True try: hid5 = self.isHiddenFifth(prevNote, note1, prevFirmus, currFirmus) except: hid5 = True try: hid8 = self.isHiddenOctave(prevNote, note1, prevFirmus, currFirmus) except: hid8 = True try: par1 = self.isParallelUnison(prevNote, note1, prevFirmus, currFirmus) except: par1 = True try: distance = interval.notesToInterval(currFirmus, note1) if distance.direction < 0: crossing = True else: crossing = False except: crossing = True goodNotes = minorScale.getConcreteMelodicMinorScale() goodNames = [note2.name for note2 in goodNotes] if validHarmony and (not par5) and (not par8) and (not hid5) and\ (not hid8) and (not par1) and (not crossing): if note1.name in goodNames: print "adding: ", note1.name, note1.octave valid.append(note1) print return valid
def intervals(notes): return [notesToInterval(notes[0], y).semiSimpleName for y in notes[1:]]
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
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 findPhraseBoundaries(book=4, madrigal=12): filename = 'monteverdi/madrigal.%s.%s' % (book, madrigal) sc = corpus.parse(filename + '.xml') analysis = corpus.parse(filename + '.rntxt') analysisFlat = analysis.flat.stripTies().getElementsByClass( roman.RomanNumeral) phraseScoresByOffset = {} for p in sc.parts: partNotes = p.flat.stripTies(matchByPitch=True).notesAndRests #thisPartPhraseScores = [] # keeps track of the likelihood that a phrase boundary is after note i for i in range( 2, len(partNotes) - 2 ): # start on the third note and stop searching on the third to last note... thisScore = 0 twoNotesBack = partNotes[i - 2] previousNote = partNotes[i - 1] thisNote = partNotes[i] nextNote = partNotes[i + 1] nextAfterThatNote = partNotes[i + 2] phraseOffset = nextNote.offset if phraseOffset in phraseScoresByOffset: existingScore = phraseScoresByOffset[phraseOffset] else: phraseScoresByOffset[phraseOffset] = 0 existingScore = 0 if thisNote.isRest == True: continue if nextNote.isRest == True: thisScore = thisScore + 10 else: intervalToNextNote = interval.notesToInterval( thisNote, nextNote) if intervalToNextNote.chromatic.undirected >= 6: # a tritone or bigger thisScore = thisScore + 10 if (thisNote.quarterLength > previousNote.quarterLength) and \ (thisNote.quarterLength > nextNote.quarterLength): thisScore = thisScore + 10 if (thisNote.quarterLength > previousNote.quarterLength) and \ (thisNote.quarterLength > twoNotesBack.quarterLength) and \ (nextNote.quarterLength > nextAfterThatNote.quarterLength): thisScore = thisScore + 10 previousNoteAnalysis = analysisFlat.getElementAtOrBefore( previousNote.offset) thisNoteAnalysis = analysisFlat.getElementAtOrBefore( thisNote.offset) if (previousNoteAnalysis.romanNumeral == 'V' and thisNoteAnalysis.romanNumeral.upper() == 'I'): thisScore = thisScore + 11 elif (previousNoteAnalysis.romanNumeral.upper() == 'II' and thisNoteAnalysis.romanNumeral.upper() == 'I'): thisScore = thisScore + 6 if thisNote.lyric is not None and thisNote.lyric.endswith('.'): thisScore = thisScore + 15 # would be higher but our lyrics data is bad. phraseScoresByOffset[phraseOffset] = existingScore + thisScore flattenedBass = sc.parts[-1].flat.notesAndRests for thisOffset in sorted(phraseScoresByOffset.keys()): psbo = phraseScoresByOffset[thisOffset] if psbo > 0: print(thisOffset, psbo) relevantNote = flattenedBass.getElementAtOrBefore(thisOffset - 0.1) if hasattr(relevantNote, 'score'): print("adjusting score from %d to %d for note in measure %d" % (relevantNote.score, relevantNote.score + psbo, relevantNote.measureNumber)) relevantNote.score += psbo else: relevantNote.score = psbo for n in flattenedBass: if hasattr(n, 'score'): n.lyric = str(n.score) sc.show()