前回の記事では、リアル音声の周波数をグラフ化し、リアル音声処理を実施する上での課題について説明しました。
今回は、リアル音声を周波数解析する上で必要となる、オーバーラップ処理と窓関数の実装について、解説していきたいと思います。
今回作成するプログラムの流れは、次のようにします。
1.音声を読み込む。
2.オーバーラップ+窓関数処理を行い、一定時間ごとの音声データ群を作成する。
3.各音声データに対してFFT処理をかけて、周波数データ群を作成する。
4.周波数データ群に逆FFT処理をかけて、音声データ群に戻す。
5.音声データ群を元の音声に戻す。
一定時間ごとの周波数データに変換して、何もせずに元の音声データに戻すプログラムです。
このプログラムができてしまえば、あとは自由に周波数解析が可能になります。
では、早速プログラム全体を見ていきましょう。
少し長いですが、やっていることは上記の通りです。
今回追加したオーバーラップ+窓関数処理を見ていきましょう。
61行目で、オーバーラップ+窓関数処理の関数「half_overlap_win」の定義を開始しています。一定時間毎の音声データを作成しますが、半分をオーバーラップさせるため「half」という名前をつけています。引数として、音声データのL、RそれぞれのデータとWavファイルの情報、切り取る大きさ(ウインドウサイズ)をインプットします。
62、63行目では、オーバーラップ+窓関数処理をかけたあとの音声データをリストとして返すための戻り値配列を作成しています。
64行目では、ウインドウサイズに合った窓関数を定義しています。窓関数は最も一般的なハニング窓を利用します。
65行目〜73行目のループで、音声信号を切り取り配列に格納していきます。
65行目は、forループのループ方法を定義しています。iを0からウインドウサイズの半分ずつ加えていき、音声の最後になるまでループします。
66行目で、endi=i+ウインドウサイズを計算しています。
67行目のif文は、endiが音声データの最後を超えてしまう場合があるので、超えていない場合と超える場合で処理を分けています。68行目、69行目は超えない場合の処理です。
68、69行目で、i〜endiで音声データを切り取り、ハニング窓を乗算した上で、戻り値配列に追加しています。
70行目〜73行目は、endiが音声データの最後を超えてしまう場合の処理です。この場合、ハニング窓の大きさも変わってくるので、71行目で再定義します。
72、73行目で、i〜音声データの最後までを切り取り、ハニング窓を乗算した上で、戻り値配列に追加しています。
74行目で、LとRそれぞれのデータを戻り値として返しています。
続いて、切り取った音声データを元の音声データに戻す関数定義について見ていきましょう。
77行目で、切り取った音声データを元の音声データに戻す関数「return_how」の定義を開始しています。「how」は「half_overlap_win」の略です。引数として、LとRそれぞれの配列とWavファイルの情報、ウインドウサイズをインプットします。
78、79行目で、LとRそれぞれの元音声データを入れるための変数を定義しています。オーバーラップしたデータを加えるため、データは予めゼロ埋めしておきます。
80行目でforループを定義しています。iを0から配列の最大サイズまでループします。ループ内ではLとRの処理を行いますが、LとRの配列サイズは同じため、Lの配列で最大サイズを取得しています。
81行目で、toにウィンドウサイズを格納していますが、配列の最後には、ウィンドウサイズ未満のデータがあるので、82行目の三項演算子により、ウィンドウサイズ未満の場合は、toに配列サイズを入れるようにします。
83行目〜85行目は、切り取った音声データの中で更にjが0からtoになるまでループします。
84、85行目で、LとRそれぞれのデータに対して、i×ウィンドウサイズの半分+jの位置に、音声データを足し込んでいきます。
86行目で、LとRそれぞれで復元した音声データを返して処理完了です。
それでは、プログラムを実行して見ましょう。
入力する音声は、前回の記事と同様「arigato.wav」です。
この音声データを本プログラムで処理して得られた「i_arigato.wav」が以下になります。
色々と処理を施したにも関わらず、ほとんど何も変わっていないことがわかると思います。
これで、周波数変更のための下準備が整いました。
次回は本プログラムに、周波数変更処理を追加して、音声処理を行いたいと思います。
コメント