音楽プログラミングの超入門(仮)

Python / 音楽情報処理 初心者が、初心者にも分かるような記事を書きたい。

【Python】時間変化するサイン波を作る

サイン波

まずは一定なサイン波について考えてみます。
周波数が F [Hz]、振幅が A のサイン波は下式で表現されます。


\begin{align}
\displaystyle
S[t] = A\sin(\frac{2\pi Ft}{\mathrm{fs}})
\end{align}


ここで t は時間インデクス、fs はサンプリング周波数、初期位相は 0 としています。これを実装すると、次のようになり

# -*- coding: utf-8 -*-
from scipy import arange, sin
from scipy import pi as mpi
from matplotlib import pylab as pl

# ===============
#  サイン波を作る
# ===============
def make_sine(F, A, fs, sec = 2.):
    ret = A * sin(2. * mpi * F * arange(int(fs * sec)) / fs)
    return ret
  
# ========
#  テスト
# ========
F_default = 10
A_default = 1
fs_default = 16000
def test():
    sine_wave = make_sine(F_default, A_default, fs_default)

    fig = pl.figure()
    fig.add_subplot(111)
    pl.plot(sine_wave)
    pl.xlim([0, len(sine_wave)])
    pl.show()

if __name__ == "__main__":
    test()

こんな感じでサイン波が作れます。
f:id:yukara_13:20131222223916p:plain

時間変化するサイン波

では、時間が経つにつれて音の高さが変わる、つまり周波数の変化するサイン波はどのように作れるでしょうか?ポイントは、周波数によって進む位相の大きさが変化することです。
 周波数が一定の場合では、時間インデクスが一つ進むごとに位相(角周波数)が  $\frac{2\pi F}{\mathrm{fs}}$ ずつ一定に進むので、上のように簡単な式で書けましたが、周波数が変わる場合は、毎回、角周波数を計算してそれを位相に足していかなければなりません。
 次のコードでは、100 ~ 1000 [Hz] まで線形的に周波数の変化するサイン波を作っています。for 文で角周波数を足していくのは不格好なので、cumsum 関数で一気に計算しているところに注意してください。

# -*- coding: utf-8 -*-
from scipy import arange, cumsum, sin, linspace
from scipy import pi as mpi

# ==========================
#  時間変化するサイン波を作る
# ==========================
def make_time_varying_sine(start_freq, end_freq, A, fs, sec = 5.):
    freqs = linspace(start_freq, end_freq, num = int(round(fs * sec)))
    ### 角周波数の変化量
    phazes_diff = 2. * mpi * freqs / fs
    ### 位相
    phazes = cumsum(phazes_diff)
    ### サイン波合成
    ret = A * sin(phazes)

    return ret


from scikits.audiolab import wavwrite
A_default = 0.5
fs_default = 16000
def test2():
    sine_wave = make_time_varying_sine(100, 1000, A_default, fs_default)
    
    wavwrite(sine_wave, "../wav/time_varying_sine_wave.wav", fs = fs_default)
    

if __name__ == "__main__":
    test2()

こんな感じの音になります。

100~1000 [Hz]、5 [sec]

ちなみに 8000 [Hz] まで変化させてみた音がこんな感じです。かなり拷問に近いので気をつけてください。

100~8000 [Hz]、20 [sec]

最後らへんエイリアシング的な何か起こしてますね、なぜか。

今回は線形単調に周波数が変化するサイン波を合成しましたが、角周波数を足し込んでいくことさえ理解していれば、どんな風に変化するサイン波でも合成できるので、挑戦してみましょう。

(振幅(音量)を固定にしていますが、これは sin 関数部に任意の振幅を掛け合わせるだけなので大丈夫でしょう。)

まとめ

高周波数のサイン波は耳に辛い。