= Note("A#")
a_sharp a_sharp
A#4
The Note
is the basic atomic unit in music.
Note (note:str, oct:int=4)
Base class for objects needing a basic __repr__
Every note has an accompanying octave oct
associated with it. This is useful later for determining intervals and playing the sound of the notes.
Each note has an integer value which shows its place in a C octave (C == 0
, C# == 1
, B == 11
, etc.)
In this example A#
should denote 10
as its integer value.
You can also do the inverse and initialize from an integer or MIDI note number.
If you would like to take the octave into account, you can use the midi
property to get the MIDI note number.
And initialize from a MIDI note number.
We use the MIDI note number to represent notes.
Using the MIDI note number we can get binary representations to convert to other formats. It also allows for very compact representations.
There are a number of ways to analyze Note
objects.
Each Note
has an accompanying octave number.
C#
has a single sharp, is not a natural, has an accidental.
Notes can be compared with each other using familiar Python operators. Here are some examples of comparison between Note
objects.
assert Note("E#") == Note("F")
assert Note("B#") == Note("C")
assert Note("C##") == Note("D")
assert Note("Fb") == Note("E")
assert Note("Abb") == Note("G")
assert Note("Bbb") == Note("A")
assert Note("Cb") == Note("B")
assert Note("C") == Note("C")
assert Note("E#") == Note("F")
assert Note("A#") != Note("B")
assert Note("F") > Note("C#")
assert Note("B#") <= Note("C")
assert Note("C") < Note("B")
assert Note("E") >= Note("E")
assert Note("C", oct=4) > Note("B", oct=3)
assert Note("C", oct=4) != Note("C", oct=5)
assert Note("C", oct=4) < Note("C", oct=5)
Adding semitones to a note will return a new note with n
semitones added above the original note.
For example, adding 1 semitone to A#
(A Sharp) will return B
.
Adding Note
objects together will form a Chord
. More on that in the Chord
section.
Note.__add__ (other)
Add n semitones.
The octave of the note is automatically updated when adding.
The %
operator is a shortcut for adding whole notes.
Note.__mod__ (other)
Add n whole notes.
We define some shortcuts to do common transpositions.
Note.alt_ext ()
Note.ext ()
Note.M13 ()
Note.m13 ()
Note.A11 ()
Note.P11 ()
Note.A9 ()
Note.M9 ()
Note.m9 ()
Note.P8 ()
Note.M7 ()
Note.m7 ()
Note.M6 ()
Note.m6 ()
Note.P5 ()
Note.TT ()
Note.P4 ()
Note.M3 ()
Note.m3 ()
Note.M2 ()
Note.m2 ()
c = Note("C")
assert c.m2() == Note("C#")
assert c.M2() == Note("D")
assert c.m3() == Note("Eb")
assert c.M3() == Note("E")
assert c.P4() == Note("F")
assert c.TT() == Note("F#")
assert c.P5() == Note("G")
assert c.m6() == Note("Ab")
assert c.M6() == Note("A")
assert c.m7() == Note("Bb")
assert c.M7() == Note("B")
assert c.P8() == Note("C", oct=c.oct+1)
assert c.m9() == Note("Db", oct=c.oct+1)
assert c.M9() == Note("D", oct=c.oct+1)
assert c.A9() == Note("D#", oct=c.oct+1)
assert c.P11() == Note("F", oct=c.oct+1)
assert c.A11() == Note("F#", oct=c.oct+1)
assert c.m13() == Note("G#", oct=c.oct+1)
assert c.M13() == Note("A", oct=c.oct+1)
For quick analysis of upper extensions o a Chord
, we add an ext
and alt_ext
method.
Upper extensions -> b9, 9, #9, 11, #11, b13, #13
[C#5, D5, D#5, F5, F#5, G#5, A5]
Altered extensions -> b9
, #9
, #11
, b13
Subtracting semitones from a Note
returns a new note with n
semitones subtracted from the original note.
For example, subtracting 1 semitone from C
returns B
. Subtracting 1 semitone from A#
returns A
.
Note.__sub__ (other)
Subtract n semitones from a note.
The //
operator is a shortcut for subtracting whole notes.
Note.__floordiv__ (other)
Subtract n whole notes
We also define shortcuts for downward intervals with d{INTERVAL}
.
Note.d_alt_ext ()
Note.d_ext ()
Note.dM13 ()
Note.dm13 ()
Note.dA11 ()
Note.dP11 ()
Note.dA9 ()
Note.dM9 ()
Note.dm9 ()
Note.dP8 ()
Note.dM7 ()
Note.dm7 ()
Note.dM6 ()
Note.dm6 ()
Note.dP5 ()
Note.dTT ()
Note.dP4 ()
Note.dM3 ()
Note.dm3 ()
Note.dM2 ()
Note.dm2 ()
b = Note("B")
assert b.dm2() == Note("A#")
assert b.dM2() == Note("A")
assert b.dm3() == Note("G#")
assert b.dM3() == Note("G")
assert b.dP4() == Note("F#")
assert b.dTT() == Note("F")
assert b.dP5() == Note("E")
assert b.dm6() == Note("D#")
assert b.dM6() == Note("D")
assert b.dm7() == Note("C#")
assert b.dM7() == Note("C")
assert b.dP8() == Note("B", oct=b.oct-1)
assert b.dm9() == Note("A#", oct=b.oct-1)
assert b.dM9() == Note("A", oct=b.oct-1)
assert b.dA9() == Note("G#", oct=b.oct-1)
assert b.dP11() == Note("F#", oct=b.oct-1)
assert b.dA11() == Note("F", oct=b.oct-1)
assert b.dm13() == Note("D#", oct=b.oct-1)
assert b.dM13() == Note("D", oct=b.oct-1)
As with the upper extensions, we also add methods to get the descending extensions with d_ext
and d_alt_ext
.
[B2, A#2, A2, G2, F#2, E2, D#2]
Note
objects can be converted to its relative major or minor. How this is converted is visualized on the circle of fifths.
For example, the relative minor of C is A. The relative major of C# is E.
minor
converts an arbitrary note to its relative minor. This means 3 semitones are subtracted from the note.
Note.minor ()
major
converts an arbitrary note to its relative major. This means 3 semitones are added to the note.
Note.major ()
Every Note
can be played as audio. A Note
is first transformed into a bytestring.
Note.get_audio_bytes (length=1, sr=44100)
Note.get_audio_array (length=1, sr=44100)
b'RIFF\xcc\xba\x06\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00D\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00data\xa8\xba\x06\x00\x00\x00\xc5\x04\x88\t'
For convenience, we can also play the audio directly.
Note.play (length=1)
The length of a specific note can be specified for the audio.
Also here, method chaining is possible.
Two Note
objects can be combined to form an Interval
.
Interval (note1:__main__.Note, note2:__main__.Note)
Initialize self. See help(type(self)) for accurate signature.
Calling interval
on a Note
object requires providing another Note
object and returns an Interval
object. A shortcut is to use the &
operator and has the same effect.
Note.__and__ (other:__main__.Note)
Note.interval (other:__main__.Note)
The full name of the interval between A#
and B
is a minor second
.
From here on in these docs we’ll use the more compact &
syntax.
The shorthand for a minor second
interval is b2
.
Interval
objects work on upper extensions up to 2 octaves.
ninth = Note("G#", oct=5) & Note("A", oct=6)
assert ninth.semitones == 13
assert ninth.long == "minor ninth"
assert ninth.short == "b9"
ninth
minor ninth (b9)
Interval
objects can be compared with each other.
C#
compared with A#
is treated as a (negative) minor 3rd.
assert (Note("C", oct=5) & Note("D", oct=5)).semitones == 2
assert (Note("C", oct=2) & Note("E", oct=2)).short == "3"
assert (Note("C", oct=5) & Note("C", oct=5)).long == "unison"
assert (Note("C", oct=5) & Note("A", oct=5)).long == "major sixth"
assert (Note("C", oct=5) & Note("B", oct=5)).long == "major seventh"
assert (Note("C", oct=5) & Note("D", oct=5)).long == "major second"
assert (Note("C", oct=5) & Note("C", oct=6)).long == "octave"
assert (Note("C", oct=5) & Note("B", oct=7)).long == "major seventh"
assert (Note("C", oct=5) & Note("F", oct=8)).long == "perfect eleventh"
assert (Note("C", oct=5) & Note("D", oct=6)).notes == [Note("C", oct=5), Note("D", oct=6)]
assert (Note("C", oct=5) & Note("D", oct=5)).notes == [Note("C", oct=5), Note("D", oct=5)]
An Interval
can also determine its type. An interval can be:
Perfect consonant
(Unison, Octave and 5th)Soft consonant
(3rds and 6ths),Mild Dissonant
(Minor 7th and Major 2nd),Sharp Dissonant
(Major 7th and Minor 2nd),Contextual
(4th)Neutral
(Tritone).Interval.is_contextual ()
Interval.is_perfect ()
Interval.is_dissonant ()
Interval.is_consonant ()
Interval.type ()
A fifth is a Perfect Consonant
.
fifth = Note("C") & Note("G")
assert fifth.type() == "Perfect Consonant"
assert fifth.is_consonant() and fifth.is_perfect()
fifth.type()
'Perfect Consonant'
A minor second is Sharp Dissonant
.
m2 = Note("C") & Note("C#")
assert m2.type() == "Sharp Dissonant"
assert m2.is_dissonant() and not m2.is_perfect()
m2.type()
'Sharp Dissonant'
A special case is the fourth which is Contextual
. This can be soft consonant or dissonant depending on the context of harmonic movement and is not feasible to determine within one interval.
fourth = Note("C") & Note("F")
assert fourth.type() == "Contextual"
assert fourth.is_contextual()
fourth.type()
'Contextual'
The Interval.type
method handles upper extensions by comparing it within the same octave. For example a flat 9 (b9
) is treated as a minor second and therefore Sharp Dissonant
.
You can add to Interval
objects to augment or diminish them.
Interval.__sub__ (other)
Interval.__add__ (other)
In this example, we augment a minor 9th interval to a major ninth (m9
-> 9
).
If we diminish the minor 9th interval it becomes an octave.