Tuning Systems
Before the signal processing is explained, a quick expose of what the piano should be tuned to must be covered
Equal Temperament Tuning ■
Modern Western music predominantly uses the equal temperament system for tuning fixed-pitch instruments like the piano. This system is a compromise designed to allow music to be played in all keys with a consistent level of consonance (ease of transposition).
The Octave and Semitones
An octave corresponds to a doubling of frequency.
The equal temperament system divides the octave into 12 logarithmically equal steps called semitones. This means the ratio of the frequencies of any two adjacent notes is constant.
The frequency ratio r for a single semitone must be such that r^{12} = 2 as to fit all 12 semitones in an octave. Therefore, this ratio is the twelfth root of 2. If f_0 is the frequency of a reference note (e.g., A4 = 440 Hz), the frequency f_n of a note n semitones away is:
f_n = f_0 \cdot \left(\sqrt[12]{2}\right)^n = f_0 \cdot (2^{1/12})^n = f_0 \cdot 2^{n/12}
In our case, we will be using the the A440 Standard. We are declaring that A4 must be 440 Hz, and that all other notes must deviate from A4 appropriately.
This chart displays the standard frequency (in Hertz) for every key on a standard 88-key piano, from A0 to C8. Notice how the A notes are perfect multiples of two of themselves. This is true for every note octave
Code
import pandas as pd
import numpy as np
def get_piano_frequencies():
"""Calculates frequencies for all 88 keys of a standard piano."""
# Note names starting from A, to align with key 1 being A0
notes = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
note_freqs = []
# Standard piano has 88 keys, A4 is the 49th key
for key_number in range(1, 89):
# Calculate half-steps from A4 (key 49)
n = key_number - 49
# Calculate frequency using the equal temperament formula
frequency = 440 * (2 ** (1 / 12)) ** n
# Determine the note name and octave for each key
note_index = (key_number - 1) % 12
octave = (key_number - 4) // 12 + 1 if key_number >= 4 else 0
note_name = notes[note_index]
note_freqs.append(
{
"key": key_number,
"Note": note_name,
"Octave": octave,
"Frequency (Hz)": frequency,
}
)
return pd.DataFrame(note_freqs)
# Create the full frequency list
df = get_piano_frequencies()
# Pivot the table to have notes as rows and octaves as columns
pivot_df = df.pivot_table(index="Note", columns="Octave", values="Frequency (Hz)")
# Order the notes correctly starting from C for musical convention
note_order = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
pivot_df = pivot_df.reindex(note_order)
# Select all available octaves (0 through 8)
# The column headers are integers, so we select them this way
final_df = pivot_df[sorted(pivot_df.columns)]
# Format the numbers and handle missing values (like C0, which doesn't exist)
# The 'na_rep' argument replaces empty cells with a dash
formatted_df = final_df.style.format("{:.2f}", na_rep="-")
# Add a caption to the final table
formatted_df.set_caption("Frequencies (Hz) by Note and Octave")| Octave | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| Note | |||||||||
| C | - | 32.70 | 65.41 | 130.81 | 261.63 | 523.25 | 1046.50 | 2093.00 | 4186.01 |
| C# | - | 34.65 | 69.30 | 138.59 | 277.18 | 554.37 | 1108.73 | 2217.46 | - |
| D | - | 36.71 | 73.42 | 146.83 | 293.66 | 587.33 | 1174.66 | 2349.32 | - |
| D# | - | 38.89 | 77.78 | 155.56 | 311.13 | 622.25 | 1244.51 | 2489.02 | - |
| E | - | 41.20 | 82.41 | 164.81 | 329.63 | 659.26 | 1318.51 | 2637.02 | - |
| F | - | 43.65 | 87.31 | 174.61 | 349.23 | 698.46 | 1396.91 | 2793.83 | - |
| F# | - | 46.25 | 92.50 | 185.00 | 369.99 | 739.99 | 1479.98 | 2959.96 | - |
| G | - | 49.00 | 98.00 | 196.00 | 392.00 | 783.99 | 1567.98 | 3135.96 | - |
| G# | - | 51.91 | 103.83 | 207.65 | 415.30 | 830.61 | 1661.22 | 3322.44 | - |
| A | 27.50 | 55.00 | 110.00 | 220.00 | 440.00 | 880.00 | 1760.00 | 3520.00 | - |
| A# | 29.14 | 58.27 | 116.54 | 233.08 | 466.16 | 932.33 | 1864.66 | 3729.31 | - |
| B | 30.87 | 61.74 | 123.47 | 246.94 | 493.88 | 987.77 | 1975.53 | 3951.07 | - |