Music Theory Primitives¶
This tutorial covers the music theory primitives available in the
coremusic.music module for working with notes, intervals, scales,
and chords.
Overview¶
The music module provides:
- Note: Musical note with MIDI number, name, octave, and frequency
- Interval: Distance between two notes with quality (major, minor, perfect)
- Scale: 25+ scale types including modes and exotic scales
- Chord: 35+ chord types from triads to extended/altered chords
Music Theory Basics¶
Notes¶
The Note class represents a musical note:
from coremusic.music.theory import Note
# Create notes from name and octave
c4 = Note('C', 4) # Middle C
fs3 = Note('F#', 3)
bb5 = Note('Bb', 5)
# Note properties
print(f"MIDI: {c4.midi}") # 60
print(f"Name: {c4.name}") # C
print(f"Octave: {c4.octave}") # 4
print(f"Frequency: {c4.frequency:.2f} Hz") # 261.63 Hz
# Create from MIDI number
a4 = Note.from_midi(69) # A440
# Transposition
e4 = c4.transpose(4) # Up 4 semitones -> E4
g3 = c4.transpose(-5) # Down 5 semitones -> G3
Intervals¶
The Interval class represents the distance between two notes:
from coremusic.music.theory import Interval
# Standard intervals (semitone values)
print(Interval.UNISON) # 0 semitones
print(Interval.MINOR_SECOND) # 1 semitone
print(Interval.MAJOR_SECOND) # 2 semitones
print(Interval.MINOR_THIRD) # 3 semitones
print(Interval.MAJOR_THIRD) # 4 semitones
print(Interval.PERFECT_FOURTH) # 5 semitones
print(Interval.TRITONE) # 6 semitones
print(Interval.PERFECT_FIFTH) # 7 semitones
print(Interval.OCTAVE) # 12 semitones
Scales¶
The Scale class provides 25+ scale types:
from coremusic.music.theory import Note, Scale, ScaleType
root = Note('C', 4)
# Diatonic scales
major = Scale(root, ScaleType.MAJOR)
natural_minor = Scale(root, ScaleType.NATURAL_MINOR)
harmonic_minor = Scale(root, ScaleType.HARMONIC_MINOR)
melodic_minor = Scale(root, ScaleType.MELODIC_MINOR)
# Modes
dorian = Scale(Note('D', 4), ScaleType.DORIAN)
phrygian = Scale(Note('E', 4), ScaleType.PHRYGIAN)
lydian = Scale(Note('F', 4), ScaleType.LYDIAN)
mixolydian = Scale(Note('G', 4), ScaleType.MIXOLYDIAN)
locrian = Scale(Note('B', 4), ScaleType.LOCRIAN)
# Pentatonic and blues
major_pent = Scale(root, ScaleType.MAJOR_PENTATONIC)
minor_pent = Scale(root, ScaleType.MINOR_PENTATONIC)
blues = Scale(root, ScaleType.BLUES)
major_blues = Scale(root, ScaleType.MAJOR_BLUES)
# Symmetric scales
whole_tone = Scale(root, ScaleType.WHOLE_TONE)
diminished = Scale(root, ScaleType.DIMINISHED)
chromatic = Scale(root, ScaleType.CHROMATIC)
# World scales
double_harmonic = Scale(root, ScaleType.DOUBLE_HARMONIC)
hungarian_minor = Scale(root, ScaleType.HUNGARIAN_MINOR)
persian = Scale(root, ScaleType.PERSIAN)
arabian = Scale(root, ScaleType.ARABIAN)
# Exotic scales
hirajoshi = Scale(root, ScaleType.HIRAJOSHI)
in_sen = Scale(root, ScaleType.IN_SEN)
iwato = Scale(root, ScaleType.IWATO)
balinese = Scale(root, ScaleType.BALINESE)
# Get scale notes
notes = major.get_notes()
print([n.name for n in notes])
# ['C', 'D', 'E', 'F', 'G', 'A', 'B']
# Get MIDI note numbers
midi_notes = major.get_midi_notes()
print(midi_notes) # [60, 62, 64, 65, 67, 69, 71]
Chords¶
The Chord class provides 35+ chord types:
from coremusic.music.theory import Chord, ChordType, Note
root = Note('C', 4)
# Triads
major = Chord(root, ChordType.MAJOR) # C, E, G
minor = Chord(root, ChordType.MINOR) # C, Eb, G
diminished = Chord(root, ChordType.DIMINISHED) # C, Eb, Gb
augmented = Chord(root, ChordType.AUGMENTED) # C, E, G#
sus2 = Chord(root, ChordType.SUS2) # C, D, G
sus4 = Chord(root, ChordType.SUS4) # C, F, G
# Seventh chords
dom7 = Chord(root, ChordType.DOMINANT_7) # C, E, G, Bb
maj7 = Chord(root, ChordType.MAJOR_7) # C, E, G, B
min7 = Chord(root, ChordType.MINOR_7) # C, Eb, G, Bb
dim7 = Chord(root, ChordType.DIMINISHED_7) # C, Eb, Gb, Bbb
half_dim7 = Chord(root, ChordType.HALF_DIMINISHED_7) # C, Eb, Gb, Bb
min_maj7 = Chord(root, ChordType.MINOR_MAJOR_7) # C, Eb, G, B
# Extended chords
dom9 = Chord(root, ChordType.DOMINANT_9) # C, E, G, Bb, D
maj9 = Chord(root, ChordType.MAJOR_9) # C, E, G, B, D
dom11 = Chord(root, ChordType.DOMINANT_11) # C, E, G, Bb, D, F
dom13 = Chord(root, ChordType.DOMINANT_13) # C, E, G, Bb, D, F, A
# Altered chords
dom7b5 = Chord(root, ChordType.DOMINANT_7_FLAT_5)
dom7b9 = Chord(root, ChordType.DOMINANT_7_FLAT_9)
dom7s9 = Chord(root, ChordType.DOMINANT_7_SHARP_9)
# Added tone chords
add9 = Chord(root, ChordType.ADD9) # C, E, G, D
six = Chord(root, ChordType.MAJOR_6) # C, E, G, A
# Get chord notes
notes = maj7.get_notes()
print([n.name for n in notes])
# ['C', 'E', 'G', 'B']
# Get MIDI note numbers
midi_notes = maj7.get_midi_notes()
print(midi_notes) # [60, 64, 67, 71]
Key Signatures¶
Work with key signatures and the circle of fifths:
from coremusic.music.theory import CIRCLE_OF_FIFTHS, KEY_SIGNATURES
# Key signatures show sharps/flats, and whether the key is minor
print(KEY_SIGNATURES['G']) # (['F#'], False) - 1 sharp, major
print(KEY_SIGNATURES['Bb']) # (['Bb', 'Eb'], False) - 2 flats, major
print(KEY_SIGNATURES['Am']) # ([], True) - no accidentals, minor
# Circle of fifths
print(CIRCLE_OF_FIFTHS)
# ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'Db', 'Ab', 'Eb', 'Bb', 'F']
Utility Functions¶
Convert between note names and MIDI numbers:
from coremusic.music.theory import midi_to_note_name, note_name_to_midi
# Name to MIDI
midi = note_name_to_midi('C', 4) # 60
midi = note_name_to_midi('A', 4) # 69
# MIDI to name, as a single string with the octave
name = midi_to_note_name(60) # 'C4'
name = midi_to_note_name(69) # 'A4'
# Note carries the two apart
from coremusic.music.theory import Note
note = Note.from_midi(60)
print(note.name, note.octave) # C 4
See Also¶
- Async Audio - Asynchronous audio processing
- Audio File Basics - Working with audio files