和音の響きはその音楽の雰囲気を分析する重要な要素です。
長/短3和音のような明るい/悲しいといった響きから、ジャジーな和音の複雑で豊かな響きまで様々です。
このような和音の響きを計算機で分析する方法はいくつかあります。
今回は、和音がどのくらい協和的かを示すモデルとして知られている不協和度曲線を紹介します。
2つの純音の不協和度
参考文献では、基本周波数がそれぞれ f1
, f2
(f1<f2
)である2つの純音の不協和度曲線は以下のように定義されています*1。
v12
は2つの純音の音量 v1
, v2
から算出される値です。
そのため、v12
の定義は
v12=v1*v2
v12=0.5*(v1+v2)
v12=(v1*v2)**0.5
などいろいろ考えられますが、参考文献では単純な積が使われています。
3種類のalphaとbetaは曲線の形状を決定するパラメタであり、参考文献では以下の値が使われています。
以上より、Pythonでクラスとして実装しました。
import numpy as np import matplotlib.pyplot as plt class Dissonance(): def __init__( self, n_semitone=12, alphas = [0.7, 1.4, 4.0], beta = 1.25 ): self.n_semitone = n_semitone self.alphas = np.array(alphas) self.beta = beta def calc_velocity(self, v1, v2): return v1 * v2 def calc_pitch_distance(self, f1, f2): return np.abs(self.n_semitone * np.log2(f2/f1)) def calc_puretones(self, f1, f2, v1=1.0, v2=1.0): """ f1, v1は値を与える。f1は基準となる純音の基本周波数 f2, v2は値もしくはnd.arrayを与える """ f2 = np.array(f2) if type(f2) in [int, float] else f2 v12 = self.calc_velocity(v1, v2) x12 = self.calc_pitch_distance(f1, f2) x12beta = x12 ** self.beta d12 = v12 * self.alphas[2] * (\ np.exp(-self.alphas[0] * x12beta) \ - np.exp(-self.alphas[1] * x12beta) ) return d12
注意として、calc_pitch_distance()
でのf1>f2
となる場合への対処です。
f1<f2
の場合の関数とf1>f2
の場合の関数はx軸で対称になることから絶対値を取ればよいことになります。
この calc_puretones()
の返り値 d12
をプロットすると、2つの純音の不協和度を算出することができます。
試しに、f1=440
として、f2
を440~880Hzまで変化させてプロットしてみます。
_x = np.arange(0, 12+0.1, 0.1) x = 440 * 2**(_x/12) dissonance = Dissonance() y = dissonance.calc_puretones(x[0], x, 1.0, 1.0)
この純音のモデルは、私たちが普段感じるように半音で隣り合う2音が鳴った時に不協和となることが反映されています。
一方で、2つの音高が離れるほど不協和を感じなくなるというモデルになっています。
後者を修正するために、倍音を考慮した不協和度を考えます。
倍音を考慮した不協和度曲線
倍音を考慮した不協和度のアイディアは単純です。
先ほどは2つの音高の基音のみを考えていました。
倍音を考慮した不協和度曲線では、2つの音高の倍音の不協和度を全て算出し合計します。
具体的には、純音の不協和度算出関数をd(f1, f2, v1, v2)
とすると、2つの音の不協和度 D12
は、
と表すことができます。
ここで、g(v, i)
は、基音に対する i
番目の倍音の音量 v_i
を算出する関数です。
例えば、v1=1.0
に対して、v1_2=0.8
、v1_3=0.64
というように倍音の音量が小さくなるというような音をモデル化することができます。
この D12
のPython実装が以下になります。先ほどのDissonance()
クラスにメソッドを追加しています。
なお、gamma
はg(v, i)
の代わりの役目をしています。
def curve(self, f1, f2, v1=1.0, v2=1.0, gamma=1.0, n_overtones=8): f2 = np.array(f2) if type(f2) in [int, float] else f2 d12 = np.zeros(f2.shape) for k in range(1, n_overtones+1): for m in range(1, n_overtones+1): d12[:] += self.calc_puretones(f1*k, f2*m, v1*(gamma**(k-1)), v2*(gamma**(m-1))) return d12
この倍音を考慮した不協和度曲線を、何倍音まで考慮するかを変えてプロットしてみました。
_x = np.arange(0, 12+0.1, 0.1) x = 440 * 2**(_x/12) dissonance = Dissonance() for n_overtones in [1,2,3,4,5,6]: y = dissonance.curve(x[0], x, 0.88, 0.88, n_overtones=n_overtones) plt.plot(x, y, label=f"n_overtones={n_overtones}")
また、不協和度曲線は1オクターブ以上でも算出することができます。
_x = np.arange(0, 24+0.1, 0.1) x = 440 * 2**(_x/12) dissonance = Dissonance() y = dissonance.curve(x[0], x, 0.88, 0.88)
以上で、2つの音高の不協和度を算出することができました。
3つ以上の音の不協和度の算出
不協和度曲線の興味深いところは、2つの音高に対する不協和度を利用することで3つ以上の音の不協和度のような値を算出できるところです。
具体的には、3つの音高(周波数) f1
, f2
, f3
について、
として2つの不協和度を合計することで算出することができます*2
この3つの音高の不協和度を算出する関数を、Dissonance
クラスに追加します。
def surface(self, f1, f2, f3, v1=1.0, v2=1.0, v3=1.0, gamma=1.0, n_overtones=6): f2 = np.array(f2) if type(f2) in [int, float] else f2 f3 = np.array(f3) if type(f3) in [int, float] else f3 d23 = np.zeros((f2.shape[0], f3.shape[0])) d123 = np.zeros((f2.shape[0], f3.shape[0])) d12 = self.curve(f1, f2, v1, v2, gamma, n_overtones) d13 = self.curve(f1, f3, v1, v3, gamma, n_overtones) for k in range(f2.shape[0]): d23[k,:] = self.curve(f2[k], f3, v2, v3, gamma, n_overtones) for m in range(f3.shape[0]): d123[k,m] = (d12[k] + d13[m] + d23[k,m])/3 return d123
f1
は固定で、f2
, f3
を1オクターブ上前で変えてみた結果をプロットしました。
_x = np.arange(0, 12, 0.1) x = 440 * 2**(_x/12) dissonance = Dissonance() z = dissonance.surface(x[0], x, x, 0.88, 0.88, 0.88)
赤色に近いほど、不協和度が高いことを表しています。
3つの音高であるため、例えば長/短/減/増三和音がどの位置にあるか探してみるとおもしろいです。
なお、協和度に注目する場合は、以下のように不協和度曲線(曲面)を反転させた方が分かりやすくなります。
d123[k,m] = -(d12[k] + d13[m] + d23[k,m])/3
最後に、D12
, D13
, D23
を個別にプロットすると以下のようになります。
まとめ
和音の協和度を算出する不協和度曲線 (Dissonance Curve) をPythonで実装しました。
本記事では3つの音高までしか扱っていませんが、4つ以上の音高にも対応可能である*3ため、セブンスコードやよりテンションコードのような複雑な和音の分析や、ヴォイシングの分析にも利用できると考えられます。
ただし、実用では曲線(曲面)の形状や値域が、適用する音色(周波数特性)に合わせて主観に合うように調整する必要があります。