Pythonでスペクトラム解析
カリンバの調律の話の続編。 左右交互に半音ずつ上がる調律に変えたら、僕の音程分解能ではさっぱり調律できなくなってしまった。そこでスペクトルアナライザを作成。とりあえず一番下の音(僕としてはドのつもり)を録音してtmp.wavという名前で保存。PythonにはNumericPythonとかがインストールされているものとする。
import wave
fi = wave.open(r"c:\tmp2.wav")
(_,_,frameRate,numFrames,_,_) = fi.getparams()
frameRate = float(frameRate)
data = fi.readframes(numFrames)
import FFT
f = FFT.fft([ord(x) for x in data])
fi.close()
fo = open(r"c:\tmp.xls", "w")
aList = []
for i in range(1, len(f)):
x = frameRate * i / numFrames
if x < 100 or x > 1000: continue
y = abs(f[i])
fo.write("%f\t%f\n" % (x, y))
aList.append((y, x))
(power, freq) = max(aList)
print power, freq
fo.close()
wavファイルを読み込んでフーリエ解析にかけて周波数を計算して、100〜1000の範囲の周波数ごとの強さをエクセルに出力。
散布図を描くとこんな感じ。
ピークの立っているところは186.34ヘルツ。ということは…1オクターブ下のラが220ヘルツだから
>>> 186 / 220.0 0.84545454545454546 >>> from math import log >>> log(0.84545454545454546) / log(2) -0.242200902416628231オクターブ下のラからさらに1/4オクターブ(半音3つ分)下か。 ファ♯かな…。絶対音階皆無。
ちなみに、今回のソースコードはいつもにもまして投げやりなのであんまり参考にはなりません。結局寝てないので。FFT呼んじゃってるからフーリエ解析の理解にはさっぱり役立たないし。まぁ、Pythonではこれくらいの行数でこれくらいのことが出来るというサンプルにでも。
さっきのコードの最後につけたし。
from math import log, pow
logFreq = log(freq)
A = log(110.0) # 2オクターブ下のラ
logOctave = log(2.0)
s = (logFreq - A) % logOctave
onkai = int(s * 12 / logOctave)
cent = (s * 12 % logOctave) * 100
strOnkai = "A, B-, B, C, C+, D, E-, E, F, F+, G, A-".split(", ")
print strOnkai[onkai], cent
これで「F+ 6.48710700099」というように表示される。ファ♯から6.5セント高い音ということ。(1セント=半音の100分の1)これでセントが0になるように調律すれば音感の鈍い僕でもばっちり調律できる…はず。