Skip to content

Instantly share code, notes, and snippets.

@romilly
Created October 12, 2023 09:32
Show Gist options
  • Save romilly/e3bb09d0b965fc5c9183f6f696b59425 to your computer and use it in GitHub Desktop.
Save romilly/e3bb09d0b965fc5c9183f6f696b59425 to your computer and use it in GitHub Desktop.
Convert a note pitch like A#4 to its frequency.
# -*- coding: utf-8 -*-
"""
Convert a note pitch like A#4 to its frequency.
"""
# Generate a unique pitch for a note based on its pitch class and octave.
def name(pitch_class: str, octave: int) -> str:
return f"{pitch_class}{octave}"
# Define the twelve pitch classes in the Chromatic Octave.
CHROMATIC_OCTAVE = "C,C#,D,D#,E,F,F#,G,G#,A,A#,B".split(',')
# Define the range of octaves to consider.
OCTAVES = range(8)
# Generate all possible note names from 'C0' to 'B7'.
PITCH_CLASS_NAMES = [name(pitch_class, octave) for octave in OCTAVES for pitch_class in CHROMATIC_OCTAVE]
# Calculate the ratio between the frequency of a note and the frequency of the semitone above it.
SEMITONE_FACTOR = 2 ** (1 / 12.0)
# Convert an index in the list of notes to its frequency.
def tone_for(i: int) -> int:
return round(440 * SEMITONE_FACTOR ** (i - 57))
# Map each note name to its frequency.
NOTE_FREQUENCIES = dict([(name, tone_for(i)) for i, name in enumerate(PITCH_CLASS_NAMES)])
# In music, some notes have two names even though they sound the same, known as enharmonics.
# Add the enharmonic notes to the NOTE_FREQUENCIES dictionary for accurate frequency lookups.
for octave in OCTAVES:
for (first, second) in [("C#", "D♭"), ("D#", "E♭"), ("F#", "G♭"), ("G#", "A♭"), ("A#", "B♭")]:
NOTE_FREQUENCIES[name(second, octave)] = NOTE_FREQUENCIES[name(first, octave)]
# Convert a note name to its frequency in the well-tempered scale.
def frequency_for_note(name: str) -> int:
if 'S' in name:
name = name.replace('S','#')
return -1 if name not in NOTE_FREQUENCIES else NOTE_FREQUENCIES[name]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment