Python | librosaを用いて騒音計を作るには?(PyAudio、matplotlib)

Python | librosaを用いて騒音計を作るには?(PyAudio、matplotlib)

前回は「音圧」の可視化を行いました。

では、実際に利用できる「騒音計」はどう作ればよいのでしょうか?

そもそもdBと「騒音」の関係性とは?

どのぐらいのデシベル数だと「騒音」と感じるのでしょうか?

埼玉の深谷市が提供しているリストを見てみます。

Pythonで騒音計を作るには?

上記の情報を踏まえ、騒音計を考えます。

前回のdBFSは「最大が0dB」として考え、-∞[dB]に向かうほど音が小さくなるよう設定しました。

音圧レベル (dB) = 20 * log10(RMS振幅 / 基準振幅)

のうち、基準振幅を「1(≒ ref =1)」として計算していましたが、この基準振幅を 人が知覚できる最小音の「2*1e-5」パスカルに設定します。

import librosa.display 
import matplotlib.pyplot as plt

y,sr = librosa.load("input_cicada.mp3")

rms=librosa.feature.rms(y=y) #RMSを計算

db=librosa.amplitude_to_db(rms,ref=2*1e-5) #dBを計算
time=librosa.times_like(db,sr=sr) #時間軸の生成

plt.xlabel("Time(s)")
plt.ylabel("dB")
plt.plot(time,db[0])

試しに蝉の鳴き声を入力してみます。

この結果が以下になります。

70dB付近で揺らいでいるのが分かります。

ストリーミングで音声取得してみる

では、マイクからストリーミングで取得した音声を扱ってみます。

サンプルの作成

ストリーミングで音声を取得し、dBを計算します。

1)pyaudioのインストール

pipでインストールします。

pip install pyaudio

2)プログラム

以下のようにコードを書きました。

バッファを設けて、値を受け渡します。

今回は取り敢えずリアルタイムでグラフが動けば良いことを前提に、グラフ描画方法はこだわっていません。

import pyaudio
import matplotlib.pyplot as plot
import numpy
import librosa.display 
import datetime

#------------------------------------------------------------
#定数
#------------------------------------------------------------
CHUNK = 2**10
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
SLEEPTIME = 0.5

#------------------------------------------------------------
#グローバル変数化
#------------------------------------------------------------
dB_list = numpy.empty(0)

#------------------------------------------------------------
#ストリーミングで音を取得
#------------------------------------------------------------
def audiostart():
    audio = pyaudio.PyAudio() 
    stream = audio.open( format = FORMAT,
                         rate = RATE,
                         channels = CHANNELS, 
                         input = True, 
                         frames_per_buffer = CHUNK)
    return audio, stream

#------------------------------------------------------------
#終了処理
#------------------------------------------------------------
def audiostop(audio, stream):
    stream.stop_stream()
    stream.close()
    audio.terminate()

#------------------------------------------------------------
#dB計算
#------------------------------------------------------------
def average_dB(buf):
    rms=librosa.feature.rms(y=buf) #RMSを計算
    dB=librosa.amplitude_to_db(rms,ref=2*1e-5) #dBを計算
    dt = datetime.datetime.today()
    avg_dB = numpy.array([dt,numpy.mean(dB)])
    print(avg_dB)
    return avg_dB #buf当たりの平均dBを返す

#------------------------------------------------------------
#グラフ描画
#------------------------------------------------------------
def read_plot_data(stream):
    global dB_list 
    data = stream.read(CHUNK)
    audiodata = numpy.frombuffer(data, dtype='int16') / float((numpy.power(2, 16) / 2) - 1) 
    dB_list = numpy.append(dB_list,average_dB(audiodata)[1])

    plot.ylim(0,100)
    plot.ylabel("dB")
    plot.plot(dB_list)
    plot.draw()
    plot.pause(SLEEPTIME)
    plot.cla()

#------------------------------------------------------------
#Main
#------------------------------------------------------------
if __name__ == '__main__':
    (audio,stream) = audiostart()
    
    while True:
        try:
            read_plot_data(stream)
        except KeyboardInterrupt:
            break

    audiostop(audio,stream)

結果を見てみます。下図のように、横軸は要素の番号、縦軸がdBでリアルタイムでの描画を行うことが出来ました。

騒音計のタタキが完成しました。

今回は以上です!

ではまた。

参考サイト

pyaudioを使って録音・再生してみよう!【pythonで音響信号処理】

エラー: データの取得に失敗しました。