pythonで音プログラミング

  • by

サウンドプログラミング

音を扱うプログラムを今回は扱っていきます。
音をやりたいというモチベーションは人それぞれだと思いますが、
pythonの様々な機能に触れたり、信号処理的な何かや数学的何かの勉強にもなるのでおすすめです。

また環境としてはpython3さえあれば記事に沿ってプログラミングできると思いますが、
Jupyter NotebookやGoogle Colabを想定して進めています。
もし、Google Colabの導入がまだであれば前回の記事をご覧ください。

Contents

  1. 音とは
  2. 音を作る・見る・聴く
  3. まとめ

1 音とは

詳しい物理的な話は抜きでプログラミングに必要な知識だけ触れたいと思います。
音には波の性質があり、波という現象を紐解くと「振幅」と「周波数」という要素に分解できます。
振幅は音の強さ、周波数は音の高さに相当します。

音の強さ

音は「波」のひとつです。媒質の粗密が伝わる波です。
より日常に即して言い換えると、空気の圧力(≒密度)の高低が、周囲の空気に伝わることで音となります。(Fig. 1)
図中では輪っかが広がるイメージですが実際は球面状に広がっています。

Fig. 1 音の放射と空気の密度のイメージ

大気圧が1013 [hPa](= 101300 [Pa])で台風などの大型低気圧だと900 [hPa](= 90000 [Pa])まで下がります。
一方、人間が耳にできる音の圧力は20 [μPa] (=0.00002 [Pa]) ~20 [Pa]くらいです。
この大気圧に対する音の圧力、すなわち音圧の小ささ、幅の広さを賢く表す単位が「デシベル(dB)」です。
今回はデシベルという単位そのものについては解説しません。
ただ、この音圧というのが音の強さに相当します。(Fig. 2)

Fig. 2 空気圧と音圧

もちろん音源からの距離によって音の強さは異なります。あくまで計測したその場での圧力を音圧としています。
音源の音の強さは[W/m^2]で表します。また音圧をdBで表現する場合は音圧レベルといいます。
ややこしいのでここらへんは別記事にしましょう。

音の高さ

ひとえに音の高さといってもいろいろあります。
例えば人の音声にしても、環境にあふれている音ひとつとっても
様々な高さの音が混ざっています。(Fig. 3 中段)
それなのに「高音が脳にいい」だとかとんでもない妄言が後を絶たないです。馬鹿者め。

Fig. 3 音声*の可視化
(上:時間波形,中:全区間でのパワースペクトル,下:スペクトログラム)

* 音声の可視化のデータには日本声優統計コーパスの”tsuchiya_normal_001.wav”を用いました。

本記事ではそういった自然界の複雑な音ではなく、人工的な単純な音を作ります。
高校数学で出てくるsin(もしくはcos)を使います。

sin波で作られた音を純音と言い、下の式で表されます。

\[y=A\times \rm{sin}(2\pi ft)\] \[(A: 振幅,f: 周波数,t: 時間)\]

Aの振幅は前の段で話した音の強さに関わるパラメータで、fは音の高さに関わるパラメータです。
周波数fは1秒間にいくつのsinの1波長(上がって下りるまでのセット)が入るかの数字です。

周波数は1秒間に何回振動するか、を表しており、「ヘルツ(Hz)」という単位を使います。
人が聴ける周波数は20~20000 [Hz]だと言われています。
Fig. 4に周波数 5[Hz]、振幅が0.8のsin波を示します。

Fig. 4 5 [Hz]で振動するsin波

一応、Fig. 4を出力するプログラムを示します。
ただ今回使ったプログラムはまとめてipynbとして共有するリンクを用意してあるので、
あくまで説明のために載せています。

import numpy as np
import matplotlib.pyplot as plt

A = 0.8
f = 5
t = np.arange(0, 1, 0.001)
y = A * np.sin(2*np.pi*f*t)

plt.plot(t, y)
plt.xlabel("time [s]")
plt.ylabel("amplitude")
plt.show()

2 音を作る・見る・聴く(再生する)

以下のプログラムをご覧ください。

import numpy as np
import matplotlib.pyplot as plt
import IPython.display

A = 0.8
f = 440
samplingrate_hz = 44100

t = np.arange(0, 1, 1 / samplingrate_hz)
y = A * np.sin(2*np.pi*f*t)

plt.plot(t, y)
plt.xlabel("time [s]")
plt.ylabel("amplitude")
plt.show()

IPython.display.Audio(y, rate = samplingrate_hz)

上を実行するとFig. 5のような状態になると思います。

Fig. 5 プログラム実行画面

作られる音ファイルはこちら。(リンクを押すと音が流れます。音量にご注意ください。)

聴いてみるとポーっとどこかで聴いたような音が流れると思います。これがsin波が440個ならんだ音です。
440 [Hz]というのは様々な音の基準になっており、ドレミ(CDE)でいったらラ(A)の音になります。

では1行ずつ読み解いていきましょう。

1~3行目 インポート

それぞれ数字や配列を扱うnumpy、グラフを描画するmatplotlib.pyplot、
そして音の出力をするIPython.displayをインポートしています。

5~7行目 パラメータ設定

振幅Aを0.8に、周波数fを440 [Hz]にしています。
また新たにサンプリング周波数samplingrate_hzを設定しています。
時間方向にどれくらい細かく見るかに相当し、今回は1秒間を44100分割しています。
サンプリング定理によって、扱う信号の2倍の周波数が必要になります。
(今回扱う信号の周波数が440 [Hz]なので、サンプリング周波数は最低でも880 [Hz]以上が必要ですが、
44100 [Hz]なのでものすごく余裕があります。)

9,10行目 時系列と出力の設定

yはひとつの関数として扱われます。時間を入力したら、-0.8~0.8の値を出力する関数です。
tはその入力にあたります。yへの入力は時刻になりますが0スタート、1終わりなので1秒分の長さを与えています。
時間方向の分解能は7行目で宣言したsamplingrate_hzによって決まります。

12~15行目 可視化(グラフ)

12行目のplt.plotでは横軸、縦軸の順でデータを与えます。
13,14行目は読んで分かる通りそれぞれの軸ラベルを設定しています。

17行目 音の出力

時間波形とサンプリング周波数を入力して音の再生ができます。
また再生ツールの右にある点が3つならんだところからダウンロードできます。

もちろんこの他に.wavファイルとして書き出すこともできますが、
今回はこの場で再生できる手法をとりました。

3 まとめ

  • 音は空気の粗密が波として伝わる現象
  • 強さ、高さ=振幅、周波数 の2つの要素をもつ
  • 純音を再生できるプログラムを作った

音プログラミングと大口叩いた割にほとんど音の説明になってしまったような…
ちなみに今回使ったプログラムもこちらで公開しております。(閲覧のみ可能です)

なんといってもnotebookの便利さが際立ちますね。
5~7行目のパラメータをいじって実行さえすればすぐ音が聞けます。matplotlibで可視化もできます。
何か変更してその出力を即座に得られるのは他のツールにはない利点だと思います。

追記(2019/04/06)
こちらのGithubページにてプログラムを公開しています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です