Pythonでお手軽音声処理(1) 音声処理の基本

シェアする

  • このエントリーをはてなブックマークに追加

こんにちは、だいぶ更新が滞ってしまいました。

ふるやん(@furuya1223)です。

今回から、「Pythonでお手軽音声処理」と題したシリーズで、音声信号処理について解説してみたいと思います。

とりあえずノイズ除去まで行けたらいいなと思っています。

初回の今回は、音声処理の基本についてです。

できるようになること

PythonでWAV形式音声ファイルの読み込みと書き込みができるようになります。

音割れさせることができるようになります。

とにかくコードが動かしたい!

こちら(GitHub)からmain.pyとsample.wavをダウンロードし、同階層に置いてmain.pyを実行してみてください。

main.pyのコメントに書いていますが、入力された音声を音割れさせるプログラムです。

需要あるのか?

音声ファイルについて

音声を扱う上で知っておくべき前提知識について書いておきます。

すでに知っている方はすっ飛ばしてください。

ファイル形式

コンピュータで扱う音声ファイルには、様々な形式があります。

パッと思いつくのは、「MP3形式」かなと思います。

「WAV形式」の一般的な認知度ってどんなもんなんでしょうかね。

音声処理では、WAV形式(.wav)の音声ファイルを利用するのが一般的です。

WAV形式というのは、音声データが圧縮されていない形式です。なので、サイズが大きいです。その代わりに、そのまま扱えます。

MP3などの圧縮された形式のファイルは、いったん非圧縮の形に変換してから使わないといけません。

そのため、このシリーズでも全てWAV形式のファイルのみ扱います。

MP3形式のファイルを扱いたい場合は、iTunesなどを使ってWAV形式に変換してください。(変換のしかたは調べてください……)

サンプルとして、JSUTコーパスに含まれる音声を1つ載せておきます。

女性が「水をマレーシアから買わなくてはならないのです」と言っている音声です(なぜこのテキストなのかは知りません)

WAVファイルの内容

WAVファイルには「ヘッダ」と呼ばれる部分とデータが記録された部分が存在します。

ヘッダには、チャンネル数(モノラルかステレオか)やサンプリングレートなどの情報が記述されていますが、とりあえずは何も考えなくていいです。

ヘッダの扱いはPythonがうまいことやってくれます。

サンプリングレートは重要な数値ですが、詳しいことは別の記事で書きます。

モノラルのWAVファイルのデータ部分には、多くの場合、符号付き16bit整数が並んでいます。

この場合、数値は -32768~32767 までの 65536(=2^16)段階となりますが、これを -1~1 の範囲にするために、32768 で割ると良いです。

逆に、音声データを出力するときは、-1~1 の範囲のデータ列を、 32768 倍して最大値を調整してから符号付き16bit整数に変換します。

まあ、とりあえずやってみましょう。

音声ファイルの読み込みと書き込み

音声ファイルの読み込みには、scipyを使用します。

numpyscipyをインストールして、Pythonから利用できる状態にしておいてください。

AnacondaでPythonを入れた場合は、すでに入っていると思います。

scipy.io.wavfile.read(ファイルパス) で音声ファイルの読み込みができます。

出力は (サンプリングレート, 音声データ) のタプルになります。

上記のpythonファイルと同階層に、先ほどのsample.wavを入れておいてください。

こうすることで、WAVファイルの読み込みができます。

出力は以下のようになると思います。

rateの値が48000というのは、1秒の音声に対して48000個のデータ値が計測されているということを表します。

dataの長さが153120なので、153120/48000=3.19秒の音声であるということになります。

サンプリングレートについて、詳しくは別記事に書きます。

音声ファイルの書き込みは、データを32768倍して-32768~32767の範囲に収めて符号付き16bit整数に変換してから、scipy.io.wavefile.write(出力ファイルパス, サンプリングレート, データ)で保存します。

ndarrayの値を指定範囲に制限する(クリッピングする)には、np.clip(ndarray, 下限, 上限)を使用します。

これで、とりあえず素通しで音声ファイルを複製するプログラムができました。

音割れさせてみる

音割れというのは、音声がマイクの最大入力レベルやスピーカーの最大出力レベルを超えたときに、クリッピングされることによって発生します。

これを意図的に起こしましょう。

クリッピングには、先ほどのnp.clip関数を使えますね。

音声を [-0.03, 0.03] の範囲にクリッピングさせてみましょう。

こうすると音量も小さくなってしまうので、適当に3倍しておきます。

この処理を、読み込みと書き込みの間に行います。

これを実行すると、このような音声がoutput.wavとして出力されます。

割れてますね。良い音割れです。

まとめ

  • 音声ファイルはWAV形式のものを使用する。
  • rate, data = scipy.io.wavfile.read(ファイルパス) で音声読み込み。
  • (rate, data はただの変数名なので、名前を変えてもいい)
  • dataは -32768~32767 の値をとるので、32768で割っておく。
  • scipy.io.wavfile.write(出力ファイルパス, サンプリングレート, 音声データ) で音声ファイルを出力。
  • 出力するときは音声データを -32768~32767 の範囲の符号付き16bit整数にしておく。
  • np.clip関数で音割れさせられる。

次回は、「matplotlibを利用して音声波形を表示」か、「サンプリングレートに関する解説」になると思います。どっちが先かは気分次第。

ノイズ除去までは書き続けるので、今後もよろしくお願いします。

ついでにツイッター(@furuya1223)フォローしていただけると、更新頻度が少し上がるかもしれません。

では。

スポンサーリンク
レクタングル(大)
レクタングル(大)

シェアする

  • このエントリーをはてなブックマークに追加

フォローする