Created
July 7, 2020 17:41
-
-
Save thorwhalen/6745b24f3966d6015b8fc4bba5aed6c7 to your computer and use it in GitHub Desktop.
Looking into the musical notes and color correspondence
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
I've often seen that “color of musical notes” thing, | |
and I always wondered about it (especially because I’d like to use it as educational support when I teach my (reluctant) | |
daughter music). | |
The mappings I see are not always consistent, but one comes up most often; | |
the one where the red-to-violet range is mapped to the C-to-B range. | |
Now this could just so happen to be correct, but the choice that C as the canonical root note of a scale seems | |
to be arbitrary, whereas red as the first color is a physical reality, leading me to think that: | |
- The choice of C as the root note was purposely based on the red-to-violet correspondence | |
- It’s a crock of s**t | |
Here's look into the numbers… | |
The conclusion is: | |
It’s a lie. At least the C -> red, D -> Orange, ..., B -> Violet is. | |
But… It does seem to correspond to an A-based scale! | |
That is A -> Red (on the orange side), B -> Yellow, C -> Green, D -> Blue, E -> Blue-Violet, F -> Red-Violet, G -> Red | |
Which now makes me think that it’s the reason why we call it “A” in the first place... | |
The following script prints: | |
abs_note log2_base_freq Color color_freq_THz | |
C 0.03 Green 566.0 | |
C# 0.11 Cyan 600.0 | |
D 0.20 Blue 638.0 | |
D# 0.28 Blue 638.0 | |
E 0.36 Violet 714.0 | |
F 0.45 Violet 714.0 | |
F# 0.53 Violet 714.0 | |
G 0.61 Red 428.0 | |
G# 0.70 Red 428.0 | |
A 0.78 Red 428.0 | |
A# 0.86 Orange 484.0 | |
B 0.95 Yellow 517.0 | |
""" | |
import requests | |
import pandas as pd | |
import numpy as np | |
import re | |
from collections import Counter | |
note_to_abs_note = lambda note: re.compile('[#A-G]+').match(note).group(0) | |
def get_notes_base_freq(): | |
url = 'https://pages.mtu.edu/~suits/notefreqs.html' | |
r = requests.get(url) | |
html = r.content | |
_, df = pd.read_html(html) | |
df.columns = ['Note', 'Frequency', 'Wavelength'] | |
df['abs_note'] = list(map(note_to_abs_note, df['Note'])) | |
df['log2_freq'] = np.log2(df['Frequency']) | |
df['log2_base_freq'] = np.mod(df['log2_freq'], 1) # to get a representative frequency number for a note | |
# the decimals=2 is what leads to a consistent note->log2_base_freq mapping: | |
df['log2_base_freq'] = np.round(df['log2_base_freq'], decimals=2) | |
assert len(Counter(df['log2_base_freq'])) == len(Counter(df['abs_note'])) # assert that we're good! | |
t = df[['abs_note', 'log2_base_freq']].groupby('abs_note').mean() | |
return t.reset_index() | |
def get_color_base_freq(): | |
url = 'https://en.wikipedia.org/wiki/Color' | |
r = requests.get(url) | |
html = r.content | |
tables = pd.read_html(html) | |
d = tables[2] # chose number 2 manually (see "the way I got the color data" section) | |
d = d[['Color', '(THz)']] | |
d = d.iloc[1:8] | |
d['(THz)'] = d['(THz)'].astype(float) | |
d['Color'] = d['Color'].replace('Violet (visible)', 'Violet') | |
t = d['(THz)'] * 1e12 # Tera means 10^12 (10 ** 12 == 1e12) | |
d['log2_base_freq'] = np.mod(np.log2(t), 1) | |
d['color_freq_THz'] = d['(THz)'] | |
del d['(THz)'] | |
return d | |
notes = get_notes_base_freq() | |
color = get_color_base_freq() | |
the_truth_about_it = pd.merge_asof(notes.sort_values('log2_base_freq'), | |
color.sort_values('log2_base_freq'), | |
on='log2_base_freq') | |
print(the_truth_about_it.to_string(index=False)) | |
""" | |
Prints: | |
abs_note log2_base_freq Color color_freq_THz | |
C 0.03 Green 566.0 | |
C# 0.11 Cyan 600.0 | |
D 0.20 Blue 638.0 | |
D# 0.28 Blue 638.0 | |
E 0.36 Violet 714.0 | |
F 0.45 Violet 714.0 | |
F# 0.53 Violet 714.0 | |
G 0.61 Red 428.0 | |
G# 0.70 Red 428.0 | |
A 0.78 Red 428.0 | |
A# 0.86 Orange 484.0 | |
B 0.95 Yellow 517.0 | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A jupyter notebook with the code, and other stuff, here: https://github.com/thorwhalen/my_notebooks/blob/master/Sound%20and%20light%20--%20the%20color%20of%20musical%20notes.ipynb