Chord

Stack of notes

The Chord class is a collection of notes played together. The name of the chord is automatically inferred from the notes.


source

Chord

 Chord (notes:List[musy.note.Note])

Base class for objects needing a basic __repr__

Initialization

c_major = Chord(["C", "E", "G"])
assert c_major.name == "C major triad"
assert c_major.oct_s_notes == ["C4", "E4", "G4"]
c_major
Chord: 'C major triad'. Notes: ['C4', 'E4', 'G4']

Chord objects can be created from a string.

cmaj7 = Chord.from_short("Cmaj7")
assert cmaj7.name == "C major seventh"
cmaj7
Chord: 'C major seventh'. Notes: ['C4', 'E4', 'G4', 'B4']

Chord objects can also be created from MIDI.

cmaj9_midi = [60, 64, 67, 71, 74]
cmaj9 = Chord.from_midi(cmaj9_midi)
assert cmaj9.midi == cmaj9_midi
assert cmaj9.s_notes == ["C", "E", "G", "B", "D"]
assert cmaj9.oct_s_notes == ["C5", "E5", "G5", "B5", "D6"]
assert cmaj9.name == "C major ninth"
assert cmaj9.root == Note("C", oct=5)
assert cmaj9.s_root == "C"
assert cmaj9.oct_s_root == "C5"

We can get the MIDI numbers for each note in a chord.

assert cmaj7.midi == [48, 52, 55, 59]
cmaj7.midi
[48, 52, 55, 59]

There is also the option to get a unique binary representation of a chord.

bin(cmaj7)
'0b100010010001000000000000000000000000000000000000000000000000'
hex(cmaj7)
'0x891000000000000'

We will treat the lowest note of a Chord as the root.

cmaj7.root
C4

Comparison

Chord objects can be compared to each other using familiar Python operators. The length of the chords and the underlying notes are compared. For example, A C major chord is technically lower than a C major 7th chord. The 1st 3 notes are the same, but Cmaj7 has an additional 4th note.

assert c_major <= cmaj7

Length is only a tie breaker in this example. For example, an E major chord is higher than a D major 7 chord, because its root note is higher.

assert Chord.from_short("E") >= Chord.from_short("Dmaj7")

Transposition

Semitones

Chord objects can be transposed in the same way as Note objects.

# Cmaj2 + 2 semitones == Dmaj7
cmaj7 + 2
Chord: 'D major seventh'. Notes: ['D4', 'F#4', 'A4', 'C#5']
# Dmaj7 > Cmaj7
cmaj7 + 2 > cmaj7
True
# Cmaj7 - 1 == Bmaj7
cmaj7 - 1
Chord: 'B major seventh'. Notes: ['B3', 'D#4', 'F#4', 'A#4']

Whole Notes

As with Note objects, there are shortcuts for transposing whole notes up and down by using the % and // operators, respectively.

assert cmaj7 + 2 == cmaj7 % 1
# Transpose up 1 whole note
cmaj7 % 1
Chord: 'D major seventh'. Notes: ['D4', 'F#4', 'A4', 'C#5']
# Transpose down 5 whole notes (Same Dmaj7 chord but 1 octave lower)
cmaj7 // 5
Chord: 'D major seventh'. Notes: ['D3', 'F#3', 'A3', 'C#4']

Note/Note and Chord/Note Multiplication

Note objects can be multiplied with other Note objects to form a Chord. Multiplying Chord objects with Note objects will add the note to the chord.


source

Chord.__mul__

 Chord.__mul__ (other)

Add a note to a chord.


source

Note.__mul__

 Note.__mul__ (other:musy.note.Note)

Form a chord from two notes.

# C/Eb slash chord
c_over_eb = Note("Eb", oct=3) * Note("C", oct=4) * Note("E", oct=4) * Note("G", oct=4)
c_over_eb
Chord: 'No chord found.'. Notes: ['Eb3', 'C4', 'E4', 'G4']

Using the syntax above, we can for example define the “mu chord” (major with add2) made famous by Steely Dan with concise code.

def mu(root: Note): return root * (root % 1) * (root % 2) * (root + 7)

c_mu = mu(Note("C"))
c_mu.notes
[C4, D4, E4, G4]

Alternatively, we can use Note shortcuts to define the same Chord.

def mu2(root: Note): return root * root.M2() * root.M3() * root.P5()

c_mu2 = mu2(Note("C"))
assert c_mu == c_mu2
c_mu2.notes
[C4, D4, E4, G4]

Inversion

Chord objects can be inverted with invert.


source

Chord.invert

 Chord.invert (n:int=1)
cmaj7.invert(2)
Chord: 'C major seventh, second inversion'. Notes: ['G4', 'B4', 'C5', 'E5']

Intervals

Interval objects can be obtained for a Chord.

Relative intervals means we start from the root note and calculate all the intervals from it.

Absolute intervals means we calculate the intervals between the notes.


source

Chord.abs_intervals

 Chord.abs_intervals ()

source

Chord.rel_intervals

 Chord.rel_intervals ()
cmaj7_rel_intvals = cmaj7.rel_intervals()
assert len(cmaj7_rel_intvals) == 3
assert cmaj7_rel_intvals[-1].short == "7"
cmaj7_rel_intvals
[major third (3), perfect fifth (5), major seventh (7)]
cmaj7_abs_intvals = cmaj7.abs_intervals()
assert len(cmaj7_abs_intvals) == 3
assert cmaj7_abs_intvals[-1].short == "3"
cmaj7_abs_intvals
[major third (3), minor third (b3), major third (3)]

Dominant

We create a single .dominant method to get the dominant chord that resolves to a given Chord. This is handy for analyzing secondary dominants and ii-V-I progressions.

By default, the dominant 7th chord (V7) is returned. If dim=True, the diminished 7th chord (vii°7) is returned.

We assume that the 1st note of the chord is the root.


source

Chord.dominant

 Chord.dominant (dim=False)

The dominant of a D major chord is A7.

d = Chord.from_short("D")
assert d.dominant() == Chord([Note("A", oct=4), Note("C#", oct=5), Note("E", oct=5), Note("G", oct=5)])
d.dominant()
Chord: 'A dominant seventh'. Notes: ['A4', 'C#5', 'E5', 'G5']

The diminished dominant (vii°7) of D major is C#°7.

assert d.dominant(dim=True) == Chord([Note("C#", oct=4), Note("E", oct=4), Note("G", oct=4), Note("A#", oct=4)])
assert d.dominant(dim=True).root == Note("C#", oct=4)
d.dominant(dim=True)
Chord: 'A# diminished seventh, first inversion'. Notes: ['C#4', 'E4', 'G4', 'A#4']

The dominant of Cmaj7 is G7.

assert cmaj7.dominant() == Chord([Note("G", oct=4), Note("B", oct=4), Note("D", oct=5), Note("F", oct=5)])
assert cmaj7.dominant().root == Note("G", oct=4)
cmaj7.dominant()
Chord: 'G dominant seventh'. Notes: ['G4', 'B4', 'D5', 'F5']

Added-Note Chords

Added-note chords are generally triads on which a 2nd (add2), 4th (add4) or 6th (add6) is added. We have method add2, add4 and add6 that adds an interval to a Chord if it doesn’t exist yet.

We also add support for upper extensions with add_ext and for removing notes with remove_ext.


source

Chord.remove_ext

 Chord.remove_ext (name:str)

source

Chord.add_ext

 Chord.add_ext (name:str)

source

Chord.add6

 Chord.add6 ()

source

Chord.add4

 Chord.add4 ()

source

Chord.add2

 Chord.add2 ()

source

Chord.add_interval

 Chord.add_interval (semitones:int)

Add note to existing chord.

An added 6th yields a 6th chord.

assert d.add6().name == "D major sixth"
d.add6()
Chord: 'D major sixth'. Notes: ['D4', 'F#4', 'A4', 'B4']

A major triad with an added 2 creates a Mu Chord, made popular by Steely Dan.

assert list(d.add2()) == [Note("D"), Note("E"), Note("F#"), Note("A")]
d.add2()
Chord: 'No chord found.'. Notes: ['D4', 'E4', 'F#4', 'A4']

You can also get upper extensions with a more general method add_ext. These methods can be chained.

For example, this line of code yields a Dadd#9addb13 chord.

d_sharp9_flat13 = d.add_ext("#9").add_ext("b13")
assert d_sharp9_flat13.root == Note("D", oct=4)
assert d_sharp9_flat13.notes == [Note("D", oct=4), Note("F#", oct=4), Note("A", oct=4), Note("F", oct=5), Note("A#", oct=5)]
d_sharp9_flat13
Chord: 'No chord found.'. Notes: ['D4', 'F#4', 'A4', 'F5', 'A#5']

Extensions can be removed with remove_ext.

Here we remove the upper extensions as well as the third to get a D power chord (D5).

d5 = d_sharp9_flat13.remove_ext("2").remove_ext("3").remove_ext("#9").remove_ext("b13")
assert d5.notes == [Note("D", oct=4), Note("A", oct=4)]
d5
Chord: 'perfect fifth'. Notes: ['D4', 'A4']

Audio

Chord objects can be played, just like Note objects.


source

Chord.play

 Chord.play (length=1)

source

Chord.get_audio_array

 Chord.get_audio_array (length=1)
cmaj7.play()
cmaj7.invert(1).play()
c_over_eb.play()
Chord.from_short("Dbdim7").play()

Chord Table

We can display all the relevant information about a chord in a Pandas DataFrame table.


source

Chord.to_frame

 Chord.to_frame ()
cmaj7.to_frame()
Notes Relative Degree Relative Interval Absolute Interval Absolute Degree
0 C 1 unison unison 1
1 E 3 major third major third 3
2 G 5 perfect fifth minor third b3
3 B 7 major seventh major third 3

Visualizing the chord as a table gives us a nice overview for analysis.

For example, in the table for the Cdim6maj7 chord below we can readily see that it constitutes of: - A diminished triad (minor third (b3), and tritone (b5)), - a major sixth (6) and - a major seventh (maj7).

Cdim6maj7 = Chord([Note("C"), Note("D#"), Note("F#"), Note("A"), Note("B")])
Cdim6maj7.to_frame()
Notes Relative Degree Relative Interval Absolute Interval Absolute Degree
0 C 1 unison unison 1
1 D# b3 minor third minor third b3
2 F# b5 tritone minor third b3
3 A 6 major sixth minor third b3
4 B 7 major seventh major second 2

PolyChord

A PolyChord is a combination of notes. Much of the functionality is inherited from the Chord object.


source

PolyChord

 PolyChord (chords:list[__main__.Chord])

Base class for objects needing a basic __repr__

Initialization

asus4 = Chord(Note(n, oct=5) for n in ["A", "D", "E"])
poly_chord = PolyChord([cmaj7, asus4])
poly_chord
PolyChord: 'C major seventh|A suspended fourth triad'. Notes: ['C4', 'E4', 'G4', 'B4', 'A5', 'D5', 'E5']

Inversion

Like Chord objects, PolyChord objects can be inverted.


source

PolyChord.invert

 PolyChord.invert (n:int=1)
poly_chord.invert(1)
PolyChord: 'C major seventh, first inversion|D suspended second triad'. Notes: ['E4', 'G4', 'B4', 'C5', 'D5', 'E5', 'A6']
poly_chord.rel_intervals()
[major third (3),
 perfect fifth (5),
 major seventh (7),
 minor thirteenth (b13),
 major ninth (9),
 major tenth (10)]
poly_chord.play()

Table

For the table display of a PolyChord we analyze the underlying chords separately.


source

PolyChord.to_frame

 PolyChord.to_frame ()
[display(t) for t in poly_chord.to_frame()];
Notes Relative Degree Relative Interval Absolute Interval Absolute Degree
0 C 1 unison unison 1
1 E 3 major third major third 3
2 G 5 perfect fifth minor third b3
3 B 7 major seventh major third 3
Notes Relative Degree Relative Interval Absolute Interval Absolute Degree
0 A 1 unison unison 1
1 D 5 perfect fifth perfect fifth 5
2 E 4 perfect fourth major second 2

TODO: Check which scales/modes the chord belongs to.

FIX: Identify all diatonic chords in a scale.

TODO: Check if chord is diatonic within a scale.