What Is A Note?

Chris Tralie, CS 372: Digital Music Processing

In [1]:
import numpy as np
import matplotlib.pyplot as plt
import IPython.display as ipd
import pandas as pd
from collections import OrderedDict

Part 1: Harmonicity

We saw at the third module that a vibrating string supports different frequencies that are integer multiples of a base frequency, known as "harmonics" or "overtones." Let's look at a few examples of base frequencies and their harmonics. We'll start with a base frequency of 220hz, and then we'll also look at a base frequency of 440z, which is known as its "octave" (the space in between these two frequencies is also referred to as an "octave"). We perceive these notes to be the same pitch, because we perceive pitch logarithmically in frequency. In other words, multiplying a sequence of frequencies by a constant amount will lead to a constant additive shift in our perception.

Finally, we'll look at frequencies at 330hz and 275hz, which are in 3/2 ratios and 5/4 ratios of 220hz, and which are known as fifths and third, respectively. And we look at another frequency, 313, which forms a "tri tone" with respect to 220hz. The plots below show notes with these base frequencies, along with their first 16 harmonics. Listen and notice that every harmonic of the octave 440hz is contained in the harmonics of 220hz, every other harmonic of 330 is contained in the harmonics of 220, and every fourth harmonic of 275 is contained in the harmonics of 220.

In [2]:
def make_html_audio(ys, sr, width=100):
    clips = []
    for y in ys:
        audio = ipd.Audio(y, rate=sr)
        audio_html = audio._repr_html_().replace('\n', '').strip()
        audio_html = audio_html.replace('<audio ', '<audio style="width: {}px; "'.format(width))
    return clips
In [3]:
sr = 44100
t = np.linspace(0, 1, sr)
pd.set_option('display.max_colwidth', None)  
tuples = []
summed = {}
for f0 in [220, 440, 330, 275, 313]:
    ys = []
    fs = (f0*np.arange(1, 17)).tolist()
    all_together = np.zeros_like(t)
    for f in fs:
        y = np.cos(2*np.pi*f*t)
        all_together += y/f # Put in less of the high frequencies
    ys = [all_together] + ys
    fs = ["All Together"] + fs
    summed[f0] = all_together
    clips = make_html_audio(ys, sr, width=50)
    tuples += [("{} hz Harmonics".format(f0), fs), ("{} hz sinusoids".format(f0), clips)]
df = pd.DataFrame(OrderedDict(tuples))
ipd.HTML(df.to_html(escape=False, float_format='%.2f'))
220 hz Harmonics 220 hz sinusoids 440 hz Harmonics 440 hz sinusoids 330 hz Harmonics 330 hz sinusoids 275 hz Harmonics 275 hz sinusoids 313 hz Harmonics 313 hz sinusoids
0 All Together All Together All Together All Together All Together
1 220 440