• 検索結果がありません。

音声信号の高音部をカットする実験

ドキュメント内 , (ページ 100-105)

第 8 章 デジタル・フィルター 97

8.6 音声信号の高音部をカットする実験

Mathematica のノートブック fourier20160114.nb2 を用意した (2016/12/22リンク切れ直しま した)。

2http://nalab.mind.meiji.ac.jp/~mk/fourier/fourier20160114.nb

fourier20160114.nb

snd = Import["http://nalab.mind.meiji.ac.jp/~mk/fourier/piano-do-mi-so.wav"]

{left, right} = snd[[1, 1]];

sr = snd[[1, 2]]

take[tbl_, t1_, t2_] := Take[tbl, {Floor[t1*sr], Floor[t2*sr]}]

take1[tbl_, t_] := Take[tbl, {Floor[t*sr], Floor[t*sr] + sr - 1}]

g = ListPlot[tbl = take1[left, 1.0], PlotRange -> All]

ListPlay[tbl]

ListPlay[tbl, SampleRate -> sr]

ListPlay[tbl, SampleRate -> sr/2]

ListPlay[tbl, SampleRate -> sr*2]

ListPlay[tbl, SampleRate -> Floor[sr*1.5]]

c = Fourier[tbl, FourierParameters -> {-1, -1}];

g = ListPlot[Abs[c], Joined -> True, PlotRange -> All]

cutoff[f_] :=

Join[Table[1, {n, f + 1}], Table[0, {n, sr - 2*f - 1}], Table[1, {n, f}]];

440.0*2^(-{9, 5, 2}/12) c2 = c*cutoff[500];

g3 = ListPlot[Abs[c2], Joined -> True, PlotRange -> All]

Export["do-mi-so-cutoff500.eps", g3]

tbl2 = Re[InverseFourier[c2, FourierParameters -> {-1, -1}]];

ListPlay[tbl2, SampleRate -> sr]

do = Re[InverseFourier[c*cutoff[300], FourierParameters -> {-1, -1}]];

domi = Re[InverseFourier[c*cutoff[360], FourierParameters -> {-1, -1}]];

domiso = Re[InverseFourier[c*cutoff[450], FourierParameters -> {-1, -1}]];

domiso2 = Re[InverseFourier[c*cutoff[900], FourierParameters -> {-1, -1}]];

original = Re[InverseFourier[c, FourierParameters -> {-1, -1}]];

ListPlay[do, SampleRate -> sr]

ListPlay[domi, SampleRate -> sr]

ListPlay[domiso, SampleRate -> sr]

ListPlay[domiso2, SampleRate -> sr]

ListPlay[original, SampleRate -> sr]

ダウンロードして、実行してみよう。

Safari でアクセスする場合は、この講義の WWW サイト http://nalab.mind.meiji.ac.jp/

~mk/fourier/を開き、fourier20160114.nb3 を Ctrl+クリックして、「リンク先のファイルを別名 でダウンロード」を選択し、自分の選ぶ場所に保存し、Mathematica で開く。

8.6.1 最初は以前やったことの復習

上から順に一つ一つ Shift + Enter で評価するか、[評価]→ [ノートブックを評価]で一気に全体 を評価する。

3http://nalab.mind.meiji.ac.jp/~mk/fourier/fourier20160114.nb

snd = Import["http://nalab.mind.meiji.ac.jp/~mk/fourier/piano-do-mi-so.wav"]

ピアノでド・ミ・ソの和音を弾いたのを録音したファイルpiano-do-mi-so.wav をインポートし、

変数snd に代入する。

{left, right} = snd[[1, 1]];

sr = snd[[1, 2]]

音声の PCM データの数値リストを変数 left, right に代入する (それぞれ左チャンネル、右チャ ンネル)。またサンプリング周波数を変数sr に代入する(値は 44100 Hzである)。

take[tbl_, t1_, t2_] := Take[tbl, {Floor[t1*sr], Floor[t2*sr]}]

take1[tbl_, t_] := Take[tbl, {Floor[t*sr], Floor[t*sr] + sr - 1}]

t1 秒後から t2 秒後までのデータを取り出す関数take[] (今回は使わない) と、t 秒後から 1秒分 のデータを取り出す関数take1[] を定義する。

(Take[] はリストの指定範囲を抜き出す関数、Floor[] は小数データを切り捨てで整数にする関

数である。)

ListPlot[tbl = take1[left, 1.0], PlotRange -> All]

最初から1.0秒のところから1秒分の左チャンネルの信号データを変数 tbl に代入し、かつプロッ トしてみる。

10 000 20 000 30 000 40 000

-0.4 -0.3 -0.2 -0.1 0.1 0.2 0.3

図 8.1: ピアノでド・ミ・ソの和音を弾く

8.6.2 サンプリング周波数を変えて再生

ListPlay[tbl, SampleRate -> sr]

数値データはListPlay[] 関数で再生(音を出力) することが可能である。その際に、サンプリン グ周波数の指定が必要である。(sndはサンプリング周波数のデータを含んでいるが、tblは信号の 数値データのみしか含んでいないので、別途指定する必要がある。)

SampleRate -> sr とすれば、正しく再生できるが、それを変えると本来の音の高さとは違う高

さで再生される。

半分にすると、1オクターブ低い音で再生される。再生時間は2倍になる。

2倍にすると、1オクターブ高い音で再生される。再生時間は1/2 になる。

サンプリング周波数を変えて遊ぶ

ListPlay[tbl, SampleRate -> sr/2]

ListPlay[tbl, SampleRate -> Floor[1.5*sr]]

(周波数を1.5倍にする。Mathematica では、サンプリング周波数は整数で指定する必要がある

ので、Floor[]を用いて整数にしている。)

8.6.3 離散 Fourier 変換してスペクトルを表示

(ここは以前やったことの軽い復習)

離散Fourier変換してスペクトルを表示

c = Fourier[tbl, FourierParameters -> {-1, -1}];

ListPlot[Abs[c], Joined -> True, PlotRange -> All]

10 000 20 000 30 000 40 000

0.005 0.010 0.015

離散 Fourier変換して、離散 Fourier係数 Cnをプロットする。変数 c は数値のリストでc[[i]] が Ci1 である(1≤i≤N =sr = 44100)。

1 秒分の信号を離散Fourier変換 (Fonurier 係数を近似計算) したので、cn,cn は周波数 nHz の 成分である。対応する離散 Fourier 係数 Cn, CNn は、それぞれc[[n+1]], c[[N-n+1]] に記憶さ れている。

ピアノのド・ミ・ソ, 3つの鍵盤を叩いて出した音であるが、ピークは3つだけでなくたくさん出 ていることが分かる。これは (もちろん) 倍音成分を含んでいるためである。

8.6.4 高い音をカットしてみる

ド・ミ・ソの基音の高さは、440×2−9/12, 440×2−5/12, 440×2−2/12Hz である。

440.0*2^(-{9, 5, 2}/12)

結果は {261.626, 329.628, 391.995}, つまりド、ミ、ソの周波数は 261.6, 329.6, 392.0 Hz で

ある。

cutoff[f_] := Join[Table[1, {n, f + 1}], Table[0, {n, sr - 2*f - 1}], Table[1, {n, f}]];

c2=c*cutoff[500];

ListPlot[Abs[c2], Joined -> True, PlotRange -> All]

cutoff[] は、f Hz より高い周波数成分はカットするための補助関数である(先頭に f+ 1 個の1, 末尾に f 個の1, その他はすべて0 という数値のリストを返す)。

c2 は 501 Hz 以上の成分を含んでいない。ド・ミ・ソの基音の部分だけしか含んでいない (2倍音

以上はカットしてある)。

10 000 20 000 30 000 40 000

0.002 0.004 0.006 0.008 0.010 0.012 0.014

逆離散Fourier変換して (音声信号に戻して) 再生

tbl2 = Re[InverseFourier[c2, FourierParameters -> {-1, -1}]];

ListPlay[tbl2, SampleRate -> sr]

501 Hz 以上をカットした音を再生して聴いてみる。(注意 以前のMathematicaでは、実部を取る

ために Re[]を施す必要がなかったが、最近の Mathematica では、tbl2 に少しでも 0 でない虚部 があると、ListPlay[tbl2,· · ·] が実行されなかった。)

その他、カットする周波数を色々変えてやってみる。

do = Re[InverseFourier[c*cutoff[300], FourierParameters -> {-1, -1}]];

domi = Re[InverseFourier[c*cutoff[360], FourierParameters -> {-1, -1}]];

domiso = Re[InverseFourier[c*cutoff[450], FourierParameters -> {-1, -1}]];

domiso2 = Re[InverseFourier[c*cutoff[900], FourierParameters -> {-1, -1}]];

original = Re[InverseFourier[c, FourierParameters -> {-1, -1}]];

ListPlay[do, SampleRate -> sr]

ListPlay[domi, SampleRate -> sr]

ListPlay[domiso, SampleRate -> sr]

ListPlay[domiso2, SampleRate -> sr]

ListPlay[original, SampleRate -> sr]

色々聴き比べてみてどうだろうか。

do はドの基音だけなのでドと聞こえる?もっとも倍音が含まれていないので、あまりピアノらし くない。

試しにやってみる? 指定した範囲の周波数成分を抜き出すことによって、ミの音だけを聴くため にはどうすれば良いか。

やり方と、その説明、そうして出来たミの音のファイルの3点をまとめよ。

ドキュメント内 , (ページ 100-105)