def testCleanFlat(self): from music21 import pitch cs = harmony.ChordSymbol(root='eb', bass='bb', kind='dominant') self.assertEqual(cs.bass(), pitch.Pitch('B-2')) self.assertIs(cs.pitches[0], cs.bass()) cs = harmony.ChordSymbol('e-7/b-') self.assertEqual(cs.root(), pitch.Pitch('E-3')) self.assertEqual(cs.bass(), pitch.Pitch('B-2')) self.assertEqual(cs.pitches[0], pitch.Pitch('B-2')) # common.cleanedFlatNotation() shouldn't be called by # the following calls, which what is being tested here: cs = harmony.ChordSymbol('b-3') self.assertEqual(cs.root(), pitch.Pitch('b-3')) self.assertEqual(cs.pitches[0], pitch.Pitch('B-3')) self.assertEqual(cs.pitches[1], pitch.Pitch('D4')) cs = harmony.ChordSymbol('bb3') # B, not B-flat self.assertEqual(cs.root(), pitch.Pitch('b2')) # b3 alteration applied to B major triad self.assertEqual(cs.pitches[0], pitch.Pitch('B2')) self.assertEqual(cs.pitches[1], pitch.Pitch('D3')) self.assertEqual(cs.pitches[2], pitch.Pitch('F#3'))
def testExportChordSymbolsWithRealizedDurations(self): gex = GeneralObjectExporter() def realizeDurationsAndAssertTags(mm: stream.Measure, forwardTag=False, offsetTag=False): mm = copy.deepcopy(mm) harmony.realizeChordSymbolDurations(mm) obj = gex.fromGeneralObject(mm) tree = self.getET(obj) self.assertIs(bool(tree.findall('.//forward')), forwardTag) self.assertIs(bool(tree.findall('.//offset')), offsetTag) # Two consecutive chord symbols, no rests cs1 = harmony.ChordSymbol('C7') cs2 = harmony.ChordSymbol('F7') m = stream.Measure() m.insert(0, cs1) m.insert(2, cs2) realizeDurationsAndAssertTags(m, forwardTag=True, offsetTag=False) # Two consecutive chord symbols, rest coinciding with first one r1 = note.Rest(type='half') m.insert(0, r1) realizeDurationsAndAssertTags(m, forwardTag=False, offsetTag=False) # One chord symbol midmeasure, no rests m.remove(cs1) m.remove(r1) realizeDurationsAndAssertTags(m, forwardTag=True, offsetTag=False) # One chord symbol midmeasure coinciding with whole note n1 = note.Note(type='whole') m.insert(0, n1) # Need an offset tag to show the -2.0 offset to get from end to midmeasure realizeDurationsAndAssertTags(m, forwardTag=False, offsetTag=True) # One chord symbol at beginning of measure coinciding with whole note m.remove(cs2) m.insert(0, cs1) realizeDurationsAndAssertTags(m, forwardTag=False, offsetTag=False) # One chord symbol at beginning of measure with writeAsChord=True # followed by a half note cs1.writeAsChord = True n1.offset = 2 n1.quarterLength = 2 realizeDurationsAndAssertTags(m, forwardTag=False, offsetTag=False)
def testHarmonyC(self): from music21 import harmony h = harmony.ChordSymbol() h.root('E-') h.bass('B-') h.inversion(2, transposeOnSet=False) #h.romanNumeral = 'I64' h.chordKind = 'major' h.chordKindStr = 'M' hd = harmony.ChordStepModification() hd.modType = 'alter' hd.interval = -1 hd.degree = 3 h.addChordStepModification(hd) s = stream.Stream() s.append(h) #s.show() raw = fromMusic21Object(s) self.assertEqual(raw.find('<root-alter>-1</root-alter>') > 0, True) self.assertEqual(raw.find('<degree-value>3</degree-value>') > 0, True) self.assertEqual( raw.find('<degree-type>alter</degree-type>') > 0, True)
def writeHalfDim(MyMeasure, RootNote, Duration, Kind): MySymbol = harmony.ChordSymbol(root=RootNote, bass=RootNote, kind='half-diminished') MySymbol.duration = Duration MyMeasure.append(MySymbol) return (MySymbol)
def writeSharpEleven(MyMeasure, RootNote, Duration, Kind): MySymbol = harmony.ChordSymbol(root=RootNote, bass=RootNote, kind=Kind) MySymbol.duration = Duration hd = harmony.ChordStepModification() hd.type = 'add' hd.interval = 1 hd.degree = 11 MySymbol.addChordStepModification(hd) MyMeasure.append(MySymbol) return (MySymbol)
def testExportNC(self): s = stream.Score() p = stream.Part() m = stream.Measure() m.append(harmony.ChordSymbol('C')) m.repeatAppend(note.Note('C'), 4) p.append(m) m = stream.Measure() m.append(harmony.NoChord()) m.repeatAppend(note.Note('C'), 2) m.append(harmony.ChordSymbol('C')) m.repeatAppend(note.Note('C'), 2) p.append(m) s.append(p) self.assertEqual(3, self.getXml(s).count('<harmony')) self.assertEqual(1, self.getXml(s).count('<kind text="N.C.">none</kind>')) self.assertEqual(1, self.getXml(s).count('<root-step text="">')) s = stream.Score() p = stream.Part() m = stream.Measure() m.append(harmony.NoChord()) m.repeatAppend(note.Note('C'), 2) m.append(harmony.ChordSymbol('C')) m.repeatAppend(note.Note('C'), 2) p.append(m) m = stream.Measure() m.append(harmony.NoChord('No Chord')) m.repeatAppend(note.Note('C'), 2) m.append(harmony.ChordSymbol('C')) m.repeatAppend(note.Note('C'), 2) p.append(m) s.append(p) self.assertEqual(1, self.getXml(s).count('<kind text="N.C.">none</kind>')) self.assertEqual( 1, self.getXml(s).count('<kind text="No Chord">none</kind>'))
def testCleanFlat(self): from music21 import harmony, pitch cs = harmony.ChordSymbol(root='eb', bass='bb', kind='dominant') self.assertEquals(cs.bass(), pitch.Pitch('B-')) self.assertEquals(cs.pitches[0], pitch.Pitch('B-2')) cs = harmony.ChordSymbol('e-7/b-') self.assertEquals(cs.root(), pitch.Pitch('E-3')) self.assertEquals(cs.bass(), pitch.Pitch('B-2')) self.assertEquals(cs.pitches[0], pitch.Pitch('B-2')) # common.cleanedFlatNotation() shouldn't be called by # the following calls, which what is being tested here: cs = harmony.ChordSymbol('b-3') self.assertEquals(cs.root(), pitch.Pitch('b-3')) self.assertEquals(cs.pitches[0], pitch.Pitch('B-3')) self.assertEquals(cs.pitches[1], pitch.Pitch('D4')) cs = harmony.ChordSymbol('bb3') self.assertEquals(cs.root(), pitch.Pitch('b3')) self.assertEquals(cs.pitches[0], pitch.Pitch('B3')) self.assertEquals(cs.pitches[1], pitch.Pitch('D#4'))
def parseTokens(mh, dst, p, useMeasures): ''' parses all the tokens in a measure or part. ''' # in case need to transpose due to clef indication from music21 import abcFormat postTransposition = 0 clefSet = False for t in mh.tokens: if isinstance(t, abcFormat.ABCMetadata): if t.isMeter(): ts = t.getTimeSignatureObject() if ts is not None: # can be None # should append at the right position if useMeasures: # assume at start of measures dst.timeSignature = ts else: dst.coreAppend(ts) elif t.isKey(): ks = t.getKeySignatureObject() if useMeasures: # assume at start of measures dst.keySignature = ks else: dst.coreAppend(ks) # check for clef information sometimes stored in key clefObj, transposition = t.getClefObject() if clefObj is not None: clefSet = False #environLocal.printDebug(['found clef in key token:', t, # clefObj, transposition]) if useMeasures: # assume at start of measures dst.clef = clefObj else: dst.coreAppend(clefObj) postTransposition = transposition elif t.isTempo(): mmObj = t.getMetronomeMarkObject() dst.coreAppend(mmObj) # as ABCChord is subclass of ABCNote, handle first elif isinstance(t, abcFormat.ABCChord): # may have more than notes? pitchNameList = [] accStatusList = [] # accidental display status list for tSub in t.subTokens: # notes are contained as subtokens are already parsed if isinstance(tSub, abcFormat.ABCNote): pitchNameList.append(tSub.pitchName) accStatusList.append(tSub.accidentalDisplayStatus) c = chord.Chord(pitchNameList) c.duration.quarterLength = t.quarterLength if t.activeTuplet: thisTuplet = copy.deepcopy(t.activeTuplet) if thisTuplet.durationNormal is None: thisTuplet.setDurationType(c.duration.type, c.duration.dots) c.duration.appendTuplet(thisTuplet) # adjust accidental display for each contained pitch for pIndex in range(len(c.pitches)): if c.pitches[pIndex].accidental is None: continue c.pitches[pIndex].accidental.displayStatus = accStatusList[ pIndex] dst.coreAppend(c) #ql += t.quarterLength elif isinstance(t, abcFormat.ABCNote): # add the attached chord symbol if t.chordSymbols: cs_name = t.chordSymbols[0] cs_name = re.sub('["]', '', cs_name).lstrip().rstrip() cs_name = re.sub('[()]', '', cs_name) cs_name = common.cleanedFlatNotation(cs_name) try: if cs_name in ('NC', 'N.C.', 'No Chord', 'None'): cs = harmony.NoChord(cs_name) else: cs = harmony.ChordSymbol(cs_name) dst.coreAppend(cs, setActiveSite=False) dst.coreElementsChanged() except ValueError: pass # Exclude malformed chord if t.isRest: n = note.Rest() else: n = note.Note(t.pitchName) if n.pitch.accidental is not None: n.pitch.accidental.displayStatus = t.accidentalDisplayStatus n.duration.quarterLength = t.quarterLength if t.activeTuplet: thisTuplet = copy.deepcopy(t.activeTuplet) if thisTuplet.durationNormal is None: thisTuplet.setDurationType(n.duration.type, n.duration.dots) n.duration.appendTuplet(thisTuplet) # start or end a tie at note n if t.tie is not None: if t.tie in ('start', 'continue'): n.tie = tie.Tie(t.tie) n.tie.style = 'normal' elif t.tie == 'stop': n.tie = tie.Tie(t.tie) ### Was: Extremely Slow for large Opus files... why? ### Answer: some pieces didn't close all their spanners, so ### everything was in a Slur/Diminuendo, etc. for span in t.applicableSpanners: span.addSpannedElements(n) if t.inGrace: n = n.getGrace() n.articulations = [] while any(t.artic): tmp = t.artic.pop() if tmp == "staccato": n.articulations.append(articulations.Staccato()) elif tmp == "upbow": n.articulations.append(articulations.UpBow()) elif tmp == "downbow": n.articulations.append(articulations.DownBow()) elif tmp == "accent": n.articulations.append(articulations.Accent()) elif tmp == "strongaccent": n.articulations.append(articulations.StrongAccent()) elif tmp == "tenuto": n.articulations.append(articulations.Tenuto()) dst.coreAppend(n, setActiveSite=False) elif isinstance(t, abcFormat.ABCSlurStart): p.coreAppend(t.slurObj) elif isinstance(t, abcFormat.ABCCrescStart): p.coreAppend(t.crescObj) elif isinstance(t, abcFormat.ABCDimStart): p.coreAppend(t.dimObj) dst.coreElementsChanged() return postTransposition, clefSet
def generateChords(numChords, kind=''): ''' Randomly generate a score of chords for use with the perceived dissonances app. These chords may be dissonant or consonant. if kind = 'diatonicTriads', only diatonic triads will be generated >>> sc = alpha.webapps.commands.generateChords(4, 'diatonicTriads') >>> a = alpha.webapps.commands.runPerceivedDissonanceAnalysis(sc, [1.2, 3.2, 5.2]) >>> chords = a['fullScore']['stream'].flat.getElementsByClass('Chord') >>> chords[0].style.color != None True >>> chords[1].style.color != None True >>> chords[2].style.color != None True >>> chords[3].style.color in [None, '#cc3300'] True >>> sc2 = alpha.webapps.commands.generateChords(4) >>> a = alpha.webapps.commands.runPerceivedDissonanceAnalysis(sc2, [1.2, 3.2]) >>> chords = a['fullScore']['stream'].flat.getElementsByClass('Chord') >>> chords[0].style.color != None True >>> chords[1].style.color != None True >>> chords[2].style.color in [None, '#cc3300'] True >>> chords[3].style.color in [None, '#cc3300'] True ''' sc = stream.Score() p = stream.Part() scl = scale.MajorScale('C') #possibleChordTypes = [l[0] for l in harmony.CHORD_TYPES.values()] possibleChordTypes = ['53', '63', '64'] if kind == 'diatonicTriads': for i in range(numChords): startDegree = random.randrange(0, 8) inversion = random.randrange(0, 3) chordPitches = [] #testDegrees = [d + startDegree - 1 for d in traidInversions[inversion] ] chordPitches = [ scl.pitchFromDegree(d + startDegree - 1) for d in traidInversions[inversion] ] chordType = possibleChordTypes[random.randrange( 0, len(possibleChordTypes))] c = chord.Chord(chordPitches) c.quarterLength = 2 p.append(c) p.makeMeasures(inPlace=True) sc.append(p) return sc else: for i in range(numChords): loPs = pitch.Pitch("C4").ps hiPs = pitch.Pitch("C#5").ps startPs = random.randrange(loPs, hiPs) startPitch = pitch.Pitch(ps=startPs) startPitchName = startPitch.name chordType = possibleChordTypes[random.randrange( 0, len(possibleChordTypes))] c = harmony.ChordSymbol(startPitchName + ',' + chordType) c.writeAsChord = True c.quarterLength = 2 c.volume.velocity = 127 p.append(c) p.makeMeasures(inPlace=True) sc.append(p) return sc
def testHarmonyB(self): from music21 import harmony from music21 import key s = stream.Stream() s.append(key.KeySignature(-2)) h1 = harmony.ChordSymbol() h1.root('c') h1.chordKind = 'minor-seventh' h1.chordKindStr = 'm7' h1.duration.quarterLength = 4 s.append(h1) h2 = harmony.ChordSymbol() h2.root('f') h2.chordKind = 'dominant' h2.chordKindStr = '7' h2.duration.quarterLength = 4 s.append(h2) h3 = harmony.ChordSymbol() h3.root('B-') h3.chordKind = 'major-seventh' h3.chordKindStr = 'Maj7' h3.duration.quarterLength = 4 s.append(h3) h4 = harmony.ChordSymbol() h4.root('e-') h4.chordKind = 'major-seventh' h4.chordKindStr = 'Maj7' h4.duration.quarterLength = 4 s.append(h4) h5 = harmony.ChordSymbol() h5.root('a') h5.chordKind = 'half-diminished' h5.chordKindStr = 'm7b5' h5.duration.quarterLength = 4 s.append(h5) h6 = harmony.ChordSymbol() h6.root('d') h6.chordKind = 'dominant' h6.chordKindStr = '7' h6.duration.quarterLength = 4 s.append(h6) h7 = harmony.ChordSymbol() h7.root('g') h7.chordKind = 'minor-sixth' h7.chordKindStr = 'm6' h7.duration.quarterLength = 4 s.append(h7) #s.show() raw = fromMusic21Object(s) self.assertEqual( raw.find('<kind text="m7">minor-seventh</kind>') > 0, True) self.assertEqual(raw.find('<kind text="7">dominant</kind>') > 0, True) self.assertEqual( raw.find('<kind text="Maj7">major-seventh</kind>') > 0, True) self.assertEqual( raw.find('<kind text="Maj7">major-seventh</kind>') > 0, True) self.assertEqual( raw.find('<kind text="m7b5">half-diminished</kind>') > 0, True) self.assertEqual(raw.find('<root-step>C</root-step>') > 0, True) self.assertEqual(raw.find('<root-alter>-1</root-alter>') > 0, True)
def writePedal(MyMeasure, RootNote, Duration, Kind): MySymbol = harmony.ChordSymbol(root=RootNote, bass=RootNote, kind='major') MySymbol.duration = Duration MyMeasure.append(MySymbol) return (MySymbol)
def transpose_chs(chs, key): # make into actual chords, and transpose each wrt the song's key key = chord.Chord(harmony.ChordSymbol(key)) return [transpose(c, key) for c in chs]
def tomusic21(ch): # flatten human-written chords into music21 chord objects return [chord.Chord(harmony.ChordSymbol(c)) for c in ch]
def get_pitch(chord): return [str(p) for p in harmony.ChordSymbol(chord).pitches]
from music21.scale import ChromaticScale import music21.harmony as harmony from orbichord.identify import chordSymbolIndex from pprint import pprint chords = OrderedDict() # Get chromatic scale pitches = ChromaticScale().getPitches('C', 'B') # Loop over all possible roots for add1 in range(13): for kind in harmony.CHORD_TYPES.keys(): for root in pitches: ref = harmony.ChordSymbol(root=root, kind=kind) basses = [None] + list(ref.pitches)[1:] inversions = [] for bass in basses: bass = bass.name if bass else None chord = harmony.ChordSymbol(root=root, kind=kind, bass=bass) if add1 > 0: chord.add(add1 - 1) key = chordSymbolIndex(chord) try: name = harmony.chordSymbolFigureFromChord(chord) except: continue if name == 'Chord Symbol Cannot Be Identified': continue if key not in chords: inversions.append(key)