用程式計算出鋼琴88個鍵的音高

雪山飛豬發表於2022-04-08

image

上篇文章,我們知道了鋼琴鍵盤的音高是其實是有規律的,如下

  1. 頻率翻倍,高一個八度
  2. 國際基準音:440Hz,鋼琴鍵盤上對應小字一組的la

小字一組的la可以看下圖
image

根據這兩個規律,我們就可以計算出所有88個琴鍵的音高(單位是頻率)。

鋼琴鍵盤是標準的十二平均律,12個鍵後頻率翻倍,那麼每個鍵的頻率倍數是固定的,也就是可以根據一個琴鍵的音高,計算出下一個琴鍵的音高。

計算鋼琴最左邊琴鍵的音高

我們知道小字一組的la頻率是440Hz,鋼琴最左邊的鍵也是la,隔了4個組,那麼最左邊琴的音高為
x * 2 * 2 * 2 * 2 = 440Hz

x = 440 / 16 = 27.5

計算每個琴鍵的倍數

每隔12個鍵音高翻倍,x^12=2
那麼每個鍵的音高倍數為2開12次方

x = pow(2, 1/12)=1.0594630943592953

python程式實現

知道了最左邊琴鍵的音高,還知道了倍數,那麼不停地乘個87次就能知道鋼琴所有琴鍵的音高了。
我們用python實現一樣

定義鋼琴鍵盤

我們先定義一個相關鋼琴鍵盤的變數

# 鋼琴鍵盤chenqionghe
keyboard = {
    "大字二組": ['A2', 'A2#', 'B2'],
    "大字一組": ['C1', 'C1#', 'D1', 'D1#', 'E1', 'F1', 'F1#', 'G1', 'G1#', 'A1', 'A1#', 'B1'],
    "大字組": ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'],
    "小字組": ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b'],
    "小字一組": ['c1', 'c1#', 'd1', 'd1#', 'e1', 'f1', 'f1#', 'g1', 'g1#', 'a1', 'a1#', 'b1'],
    "小字二組": ['c2', 'c2#', 'd2', 'd2#', 'e2', 'f2', 'f2#', 'g2', 'g2#', 'a2', 'a2#', 'b2'],
    "小字三組": ['c3', 'c3#', 'd3', 'd3#', 'e3', 'f3', 'f3#', 'g3', 'g3#', 'a3', 'a3#', 'b3'],
    "小字四組": ['c4', 'c4#', 'd4', 'd4#', 'e4', 'f4', 'f4#', 'g4', 'g4#', 'a4', 'a4#', 'b4'],
    "小字五組": ['c5']
}

為了友好展示,我們放入DataFrame中檢視

keybord_data={k: [*v, *[""]*(12-len(v))] for k, v in keyboard.items()}
df = pd.DataFrame(keybord2)

輸出一下
image
OK,這裡我們就先把鋼琴鍵盤弄出來了。

計算每個琴鍵的音高

# python
data = {}

start = 440 / 16
loop = math.pow(2, 1 / 12)
i = 0
for groupName, group in keyboard.items():
    for name in group:
        if name == "A2":
            current = start
        else:
            current = current * loop
        data[name] = name + ": " + str(round(current,3))
        i = i + 1

data這個陣列儲存了每個琴鍵的音高
image

展示琴鍵音高

df.replace(new_data)

檢視一下
image
這樣就計算出了所有琴鍵的音高,perfect~

延伸一下,泛音配比決定了音色,那麼我們是不是也可以用程式控制泛音配比來調音呢?

相關文章