【python】波形の表示(モノラル・ステレオ)【サウンドプログラミング】
こんにちは,1000chです. 音系VR研究してるんですーっていう割に信号処理能力が雑魚過ぎるので, ちょっとまじめにサウンド処理を勉強しようと思いました. てなわけで久しぶりにこの本でお勉強することにします.
ディジタル・サウンド処理入門―音のプログラミングとMATLAB(Octave・Scilab)における実際 (ディジタル信号処理シリーズ)
- 作者: 青木直史
- 出版社/メーカー: CQ出版
- 発売日: 2006/03
- メディア: 単行本
- 購入: 2人 クリック: 28回
- この商品を含むブログ (10件) を見る
MatlabやらOctaveやらを使って信号処理をする本です. 自分はMatlabは持っていないですが,理論の紹介があって実際のコードがあって,という流れで紹介しているので なかなか参考になります.というかかなりわかりやすい本だと思います.
今まで理論部分だけ読んで「ふーん」となってはすぐに忘れるを繰り返していました. そこで.キチンと自分で手を動かして理論を身につけてこうと思います!
実装として,python,Max/MSPあたりを使って遊んでいく所存です. python使っての信号処理に関してはこちらを, Max/MSPの使い方に関しては公式のチュートリアルを参考にしていきます. (前者のサイトは非常に丁寧に紹介してくださっているため,なるべく見ずにコーディングしてからの答え合わせ,という参考にしようと思っています)
waveファイルの読み込み
目下の目標は,「波形を直接弄ってエフェクトをかけること」です. という訳で今回は,「waveファイルを読み込んで数値データとして扱う」事を目指します. 先ほど紹介したこちらが非常に参考になります.
pythonでは標準でwaveモジュールが用意されているので,こちらを使えば波形の読み込みは簡単そうです. ただし読み込まれるデータはバイナリなので,適宜数値に変換する必要があります. 今回はnumpyのfrombuffer関数を利用することにしました. 波形プロットはmatplotlibを使えばokですね.
それでは,waveファイルを読み込んでその波形を表示してみます. 以下がコード.
#coding:utf-8 import wave import numpy as np import matplotlib.pyplot as plt def wave_plot(filename): # open wave file wf = wave.open(filename,'r') print(wf.getparams()) # load wave data chunk_size = 1024 amp = (2**8) ** wf.getsampwidth() / 2 data = wf.readframes(chunk_size) # バイナリ読み込み data = np.frombuffer(data,'int16') # intに変換 data = data / amp # 振幅正規化 # make time axis rate = wf.getframerate() # フレームレート[1/s] size = float(chunk_size) # 波形サイズ x = np.arange(0, size/rate, 1.0/rate) # # plot plt.plot(x,data) plt.show()
このプログラムを使って,波形を見てみます. audacityを使って440Hzのサイン波を生成しました. こんなんです.
実行結果
いい感じにplotできていますねー.
試しにのこぎり波もplotしてみます. 同じくaudacityを使ってこんなのを生成しました.
実行結果
本当にギザギザです!
ステレオ波形の表示
ここまで表示してきた波形はモノラル音源のものでした. ではここで,ステレオ音源を表示しようとするとどうなるのでしょう?
試しに,右にサイン波,左にのこぎり波の音源を作ってみました.
試してみると,
# (中略) File "/Users/masa/.virtualenvs/py3/lib/python3.3/site-packages/matplotlib/axes.py", line 239, in _xy_from_xy raise ValueError("x and y must have same first dimension") ValueError: x and y must have same first dimension
起こられました. ステレオ音源なのでデータ数が会わないんですね. 調整してみるとこんな感じに.
かっこいい!
けど明らかに波形がおかしいです.
ステレオ音源だとLRの要素が交互に配置されているため,このようなことになるのですね.
であれば,plotするデータを1つとびにすればよさそうです.
pythonのリストであればlist[::2]
とか書けばいけそう.
というわけで先ほどのコードの一部を書き換えます.
#coding:utf-8 import wave import numpy as np import matplotlib.pyplot as plt def wave_plot(filename): # open wave file wf = wave.open(filename,'r') channels = wf.getnchannels() # 追記 print(wf.getparams()) # load wave data chunk_size = 256 amp = (2**8) ** wf.getsampwidth() / 2 data = wf.readframes(chunk_size) # バイナリ読み込み data = np.frombuffer(data,'int16') # intに変換 data = data / amp # 振幅正規化 # make time axis rate = wf.getframerate() size = float(chunk_size) x = np.arange(0, size/rate, 1.0/rate) # plot マルチチャンネルに対応 for i in range(channels): plt.plot(x,data[i::channels]) plt.show()
これでplotしてみます.
青と緑で別々の波形を表示することができました!
これでステレオ波形であったとしても,サウンドを数値として扱えるようになりました. エフェクトをかけるためのお膳立ては整った!
これから
しかし,波形をただ扱えるだけではまだまだエフェクトは作れません. エフェクトを書けるフィルタの設計のためには,まだまだ勉強する要素がたくさんあります. エフェクトの処理自体は,単純なFIRであればフレーム毎にゲインをかけて総和をとるだけです. 単純なエフェクタ(オーバードライブとかコンプレッサとか)ならこれだけでも実現できてしまいます.
しかし,複雑なエフェクト(コーラスとかノイズゲートとか)では,そうもいきません. これらを設計する為には音情報を時間領域のデータから周波数領域のデータに変換する必要があります. デジタル信号処理においては,いわゆる離散フーリエ変換(DFT)というやつにあたります. 周波数領域において適切なフィルタを設計し,これを逆離散フーリエ変換(IDFT)で時間領域のデータにもどすことで,初めて有効なフィルタが設計できるのです.
まだまだ先は長いですが,少しずつ身につけていこうと思います. さーて,がんばろー.
おまけ
ちなみに波形の表示ですが,Max/MSPだとこんな感じです.
ああ,なんと簡単なのでしょう笑 まぁ,理論を勉強するのは重要ですよね!