おしゃべりする。

前回の記事で、フォルマント合成をしました。今回はマイクから入力した声の固定した周波数の振幅を検出し、その周波数のサインウェーブをいくつか作り合成して、ロボットボイスを生成します。なんかボコーダです。さて、具体的に難しいのはマイクから入力した声のフォルマント周波数の振幅を得ること。マイクから入力した音にオクターブ毎に配置したバンドパス・フィルタを通過させ、その振幅を活用します、つまり正確に得るのではなく"おおよそ"です。半オクターブ毎に配置すると精度は良くなるでしょう。

from sndobj import *
import time

thread = SndThread()

mic_in = SndRTIO(2, SND_INPUT)  #マイク入力
snd_in = SndIn(mic_in, 1)
thread.AddObj(mic_in, SNDIO_IN)
thread.AddObj(snd_in)

  #オクターブ毎にバンドパス・フィルタを配置する
tmp_freq = [110, 220, 440, 880, 1760]
tmp_freq_size = len(tmp_freq)
band = []
for i in range(tmp_freq_size):
    band.append(Reson(tmp_freq[i], 40, snd_in))
    thread.AddObj(band[i])

  #オクターブ毎にオシレータを配置する
tab = HarmTable(4096, 1, 1)
osc = []
mix = Mixer()
thread.AddObj(mix)
for i in range(tmp_freq_size):
    osc.append(Oscili(tab, tmp_freq[i], 0, None, band[i]))
    mix.AddObj(osc[i])
    thread.AddObj(osc[i])

out = SndRTIO(mix)
thread.AddObj(out, SNDIO_OUT)

thread.ProcOn()
time.sleep(30)
thread.ProcOff()

5つのバンドパスフィルタで得た振幅を、5つのオシレータの振幅にしています。もちろんそれらの周波数は同じになります。
声に直接フィルタを掛けて声質を変えるのではなく、情報を元に他の音で精度を下げて模倣するので、いい意味で仕方なく声質がかわるという感じです。