Files
pytheory/examples/overtone_series.py
T
kennethreitz 9da3ac8b28 Add 12 example scripts showcasing pytheory features
- 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>
2026-03-22 20:27:18 -04:00

69 lines
2.5 KiB
Python

"""Explore the overtone series — nature's chord."""
from pytheory import Tone, Chord
a4 = Tone.from_string("A4", system="western")
print("The Overtone Series")
print("=" * 65)
print()
print("When you play a note, you're actually hearing many frequencies")
print("at once. The fundamental plus its integer multiples:")
print()
print(f"{'Harmonic':>9s} {'Frequency':>10s} {'Nearest Note':>13s} {'Interval from Root'}")
print(f"{'' * 9} {'' * 10} {'' * 13} {'' * 25}")
overtones = a4.overtones(16)
for i, hz in enumerate(overtones, 1):
nearest = Tone.from_frequency(hz)
if i == 1:
interval = "Fundamental"
else:
interval = a4.interval_to(nearest)
print(f"{i:>9d} {hz:>10.1f} {nearest.full_name:>13s} {interval}")
# ── Why Chords Sound Good ───────────────────────────────────────────────
print()
print("Why the Major Triad Sounds 'Natural'")
print("=" * 65)
print()
print("The first 6 harmonics contain: root, octave, 5th, 2nd octave, 3rd, 5th")
print("That's a major triad! The major chord is literally embedded in physics.")
print()
c4 = Tone.from_string("C4", system="western")
harmonics = c4.overtones(6)
harmonic_names = [Tone.from_frequency(hz).name for hz in harmonics]
unique = []
for n in harmonic_names:
if n not in unique:
unique.append(n)
print(f" First 6 harmonics of C: {', '.join(harmonic_names)}")
print(f" Unique pitch classes: {', '.join(unique)}")
print(f" C major triad: C, E, G")
print()
# ── Shared Overtones = Consonance ───────────────────────────────────────
print("Shared Overtones Between Intervals")
print("=" * 65)
print()
print("The more overtones two notes share, the more consonant they sound.")
print()
root = Tone.from_string("C4", system="western")
root_overtones = set(round(h, 1) for h in root.overtones(12))
for semitones, label in [(7, "Perfect 5th (C→G)"),
(4, "Major 3rd (C→E)"),
(5, "Perfect 4th (C→F)"),
(3, "Minor 3rd (C→Eb)"),
(6, "Tritone (C→F#)"),
(1, "Minor 2nd (C→C#)")]:
other = root + semitones
other_overtones = set(round(h, 1) for h in other.overtones(12))
shared = root_overtones & other_overtones
print(f" {label:25s} {len(shared):2d} shared overtones (of first 12)")