Author
Affiliation

Cam

Anauseam

Published

2026-03-31

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.

Figure 1: Piano Octaves

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.

Figure 2: Equal Temperament Octave

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")
Table 1: 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 -