PyOpenGLでwavファイルの波形を表示させた

wave標準モジュールを使った自作wavユーティリティとOpenGLpythonバインディングのPyOpenGLを使ってwavファイルの波形を表示させてみた。pythonはwavファイルを扱うモジュールが標準であるのでバイナリファイルフォーマットをパースする処理は全てライブラリに任せられる。
それとpythonでwavのプログラムするとビットレートやチャンネル数の違いを簡単に吸収できるのでCで組むよりずっと楽に感じる。速度は・・比べてないけどCのがずっと早いと思う。

サイン波

[,h200]

方形波

[,h200]

のこぎり波

[,h200]

三角波

[,h200]

wavファイルのデータフォーマットは以下の書籍を参考にさせてもらった。始めてサウンドプログラミングする自分にとってプログラムコードが沢山収録されているこの本はわかりやすいと感じた。

WAVプログラミング―C言語で学ぶ音響処理

WAVプログラミング―C言語で学ぶ音響処理

以下のような感じに抽象化してwavファイルを作成しそれをPyOpenGLで表示させた。

  • WaveInfoクラスはwavデータのチャンネル数、ビットレート、サンプリング周波数、オーディオフレーム数の情報を保持するクラス。
  • AudioFrameクラスは音の記憶単位を保持するクラスで、チャンネル数が1のときvalueプロパティ、2のときleft,rightプロパティをもち、それぞれへの数値の代入は内部的にはメンバ変数によってバインドされたwavの生データへの代入になる。またAudioFrame,intに対する四則演算がオーバーロードされているのでチャンネル数の違いを簡単に吸収できる。
  • Waveオブジェクトは、概念的にはWaveInfoオブジェクトとAudioFrame(音の記憶単位)の配列をメンバに持つように振舞う。実際はWaveInfoオブジェクトと生データをメンバに持つクラス。そのほか、WaveInfoオブジェクトによって指定されたビットレートにおける最大値、最小値、無音の値を表すread onlyなプロパティ、maxvalue,minvalue,silentを持つ。
  • Waveオブジェクトは初期化時にファイル名、またはWaveInfoオブジェクトを受け取れる。このとき、WaveInfoオブジェクトと同時にWaveInitオブジェクトを渡すことができる。この場合データのセットアップ後にWaveInit.initメソッドを呼びデータを初期化する。

たとえば、「ラ」の音(440Hz)を作りたい場合

Wave(WaveInfo(2, 16, 44100, 44100), SinWaveInit(440))

のようになる。また、上に紹介した本ででてくるいくつかの課題は以下のように書ける。

ステレオwavファイルの左のチャンネルの音を消す

wav = Wave("music.wav")
for frame in wav:
    frame.left = wav.silent

ステレオwavファイルの左右のチャンネルの音を交換する

wav = Wave("music.wav")
for frame in wav:
    frame.left, frame.right = frame.right, frame.left

音量を半分に

wav = Wave("music.wav")
for i in xrange(len(wav)):
    wav[i] = wav[i] / 2

最後に、http://humansci.let.hokudai.ac.jp/g/toyo/matlab.htmlにある「あ」の音の波形を表示させてみた。
[,h200]