mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 14:50:18 +00:00
9da3ac8b28
- circle_of_fifths.py — visualize keys around the circle - chord_identifier.py — identify chords from notes and fingerings - key_explorer.py — explore keys, signatures, progressions, borrowed chords - temperament_comparison.py — compare equal, Pythagorean, and meantone - chord_tension.py — analyze tension, consonance, and voice leading - world_scales.py — scales from 6 musical traditions - fretboard_explorer.py — instruments, tunings, capo transposition - midi_converter.py — MIDI ↔ note ↔ frequency reference - progression_writer.py — famous progressions, Nashville numbers, random generation - interval_trainer.py — interval names, songs, and consonance ranking - overtone_series.py — harmonics and why chords sound good - key_detection.py — detect keys from melodies and chord progressions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
2.2 KiB
Python
65 lines
2.2 KiB
Python
"""Detect the key of a melody or chord progression."""
|
|
|
|
from pytheory import Key, Chord
|
|
|
|
print("Key Detection")
|
|
print("=" * 55)
|
|
print()
|
|
|
|
# ── Detect from Melody Notes ────────────────────────────────────────────
|
|
|
|
melodies = [
|
|
("Twinkle Twinkle", ["C", "G", "A", "F", "E", "D"]),
|
|
("Happy Birthday", ["G", "A", "B", "C", "D", "F#"]),
|
|
("Yesterday", ["F", "E", "D", "C", "Bb", "A", "G"]),
|
|
("Minor melody", ["A", "B", "C", "D", "E", "F", "G"]),
|
|
("Blues lick", ["E", "G", "A", "B", "D"]),
|
|
("Chromatic fragment", ["C", "C#", "D", "D#", "E"]),
|
|
]
|
|
|
|
print("Detecting key from melody notes:")
|
|
print()
|
|
for label, notes in melodies:
|
|
key = Key.detect(*notes)
|
|
print(f" {label:22s} {', '.join(notes):30s} → {key}")
|
|
|
|
# ── Detect from Chord Progression ──────────────────────────────────────
|
|
|
|
print()
|
|
print("Detecting key from chord tones:")
|
|
print()
|
|
|
|
progressions = [
|
|
("I-IV-V", [("C", "E", "G"), ("F", "A", "C"), ("G", "B", "D")]),
|
|
("Pop in G", [("G", "B", "D"), ("D", "F#", "A"), ("E", "G", "B"), ("C", "E", "G")]),
|
|
("Jazz ii-V-I", [("D", "F", "A"), ("G", "B", "D", "F"), ("C", "E", "G", "B")]),
|
|
]
|
|
|
|
for label, chord_tones in progressions:
|
|
# Collect all unique note names
|
|
all_notes = set()
|
|
for tones in chord_tones:
|
|
all_notes.update(tones)
|
|
|
|
key = Key.detect(*all_notes)
|
|
chord_names = [Chord.from_tones(*t).identify() for t in chord_tones]
|
|
print(f" {label:15s} {' → '.join(chord_names):40s} → {key}")
|
|
|
|
# ── All 24 Keys ─────────────────────────────────────────────────────────
|
|
|
|
print()
|
|
print("All 24 Major and Minor Keys")
|
|
print("=" * 55)
|
|
print()
|
|
|
|
for key in Key.all_keys():
|
|
sig = key.signature
|
|
acc = ", ".join(sig["accidentals"]) if sig["accidentals"] else "none"
|
|
rel = key.relative
|
|
print(
|
|
f" {str(key):12s} "
|
|
f"{sig['sharps']}# {sig['flats']}b "
|
|
f"({acc:15s}) "
|
|
f"rel: {rel}"
|
|
)
|