ラズパイでチャイム検知してみた Part1

# はじめに
自宅不在時の来客を通知してくれるシステムが欲しいなーと思い実装することにしました。
（コロナの影響で外出の機会が極端に減ったが...）

検知方法は、家に設置しているラズパイにマイクを接続し、生活音の中からチャイム音を検出しようと考えています。
また、使用言語はpython、パッケージPyAudioを使って生活音を取得します。

本記事では、PyAudioを使ってチャイム音を取得し、FFTでチャイム音の特徴を抽出するところまで記載します。

# 実装
ラズパイでいきなり動かす前に、macbookでPyAudio使ってみました。
その際の手順、コードを記載します。

## 環境

```terminal
$ brew --version
Homebrew 2.2.15-35-g11f50cf
$ pip3 -V
pip 19.0.3
$ python3 -V
Python 3.7.3
```

## PyAudioのインストール
pyaudioのインストールにportaudioが必要なため、先にportaudioをインストールします。

```terminal
$ brew install portaudio
$ pip3 install pyaudio
```

## 接続中の入力デバイスの確認
PyAudioを使う際に、入力デバイス(マイク)の情報を設定する必要があります。
下記のコードで入力デバイスの情報を確認できます。

```check_audio_device.py
import pyaudio

audio = pyaudio.PyAudio()
for i in range(audio.get_device_count()):
    print(audio.get_device_info_by_index(i))
```

↓実行した結果

```terminal
$ python3 check_audio_device.py 
{'index': 0, 'structVersion': 2, 'name': 'Built-in Microphone', 'hostApi': 0, 'maxInputChannels': 2, 'maxOutputChannels': 0, 'defaultLowInputLatency': 0.0029478458049886623, 'defaultLowOutputLatency': 0.01, 'defaultHighInputLatency': 0.01310657596371882, 'defaultHighOutputLatency': 0.1, 'defaultSampleRate': 44100.0}
{'index': 1, 'structVersion': 2, 'name': 'Built-in Output', 'hostApi': 0, 'maxInputChannels': 0, 'maxOutputChannels': 2, 'defaultLowInputLatency': 0.01, 'defaultLowOutputLatency': 0.010929705215419501, 'defaultHighInputLatency': 0.1, 'defaultHighOutputLatency': 0.02108843537414966, 'defaultSampleRate': 44100.0}
{'index': 2, 'structVersion': 2, 'name': 'USB PnP Audio Device', 'hostApi': 0, 'maxInputChannels': 1, 'maxOutputChannels': 0, 'defaultLowInputLatency': 0.0057083333333333335, 'defaultLowOutputLatency': 0.01, 'defaultHighInputLatency': 0.015041666666666667, 'defaultHighOutputLatency': 0.1, 'defaultSampleRate': 48000.0}
seakanoMacBook-Pro:chime_recognition seaka$ 
```

今回はUSB接続した(ラズパイでも使用する)マイクで音声データを取得するため、indexが2のデバイス情報を参照します。

- index ... 2
- maxInputChannels ... 1
- defaultSampleRate ... 48000.0

使用するデバイスの情報を取得したので、早速コードを書いてみましょう。
下記のコードを実行すると、音声データを取得しはじめます。
Ctrl+Cで停止させると、実行開始から終了までの音声データをプロットし、その後FFTした結果が表示されます。
（横軸は時間(秒)、縦軸は振幅）

```audio_plot.py
import pyaudio
import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft

FORMAT      = pyaudio.paInt16
CHANNELS    = 1         # maxInputChannels
RATE        = 48000     # defaultSampleRate
CHUNK       = 1024
IDINDEX     = 2         # index

count = 0
x = []
y = []

audio = pyaudio.PyAudio()
stream = audio.open(
     format = FORMAT
    ,channels = CHANNELS
    ,rate = RATE
    ,frames_per_buffer=CHUNK
    ,input=True
    ,output=False
)

while stream.is_active():
    try:
        input = stream.read(CHUNK, exception_on_overflow=False)
        ndarray = np.frombuffer(input, dtype='int16')
        for i in ndarray:
            count = count + 1
            data = i.item()
            seconds = count/RATE    # 経過時間を取得
            x.append(seconds)
            y.append(data)
            # print(seconds, data)
    except KeyboardInterrupt:
        break

plt.plot(x, y)
plt.show()

freq = np.linspace(0, RATE, count)
yf = np.abs(fft(y))
yf = yf * yf
plt.plot(freq[0:int(count/2)], yf[0:int(count/2)])
plt.show()


stream.stop_stream()
stream.close()
stream.terminate()
```

チャンネル数やサンプリング数を正確に設定しないと、エラーが発生するため注意が必要です。
私はここで少しつまづきました。


作成後、テストで1000Hzの音声を流してプロット結果を表示してみました。以下がその結果です。

> 図1. 1000Hz音声の波形
![スクリーンショット 2020-12-13 15.47.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108396/d12aeee3-acbc-a6de-b211-18fb1b8abfb6.png)


図1より音声を取得できてそうなことがわかります。

> 図2. 1000Hz音声をFFTした結果
![スクリーンショット 2020-12-13 15.48.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108396/ea0a7861-8f66-77c1-01c7-d4c4017f87fc.png)

図2より、1000Hz（横軸）らへんでピークが立っていることが分かります。正常にFFTできてそうです。


次に、チャイム音を取得してプロットしてみました。

> 図3. チャイム音の波形
![スクリーンショット 2020-12-13 15.52.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108396/c3741e88-e561-1e21-2a77-210238c4f15e.png)

チャイムぽい波形が出てます。

> 図4. チャイム音をFFTした結果
![スクリーンショット 2020-12-13 15.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108396/f1eb9f46-98b5-032b-b13e-f4adbef48d98.png)

ちょっと見にくいですが、1500Hz、2000Hz、3500Hzらへんでピークが立っています。
この特徴を使えば、生活音からチャイム音を抽出できそうです。

# 今後
本記事では、ラズパイとマイクを使って、生活音からチャイム音を抽出する方法について書きました。
次は、今回わかった特徴を元に、実際にチャイム検知システムを作りたいと思います。
最終的には、チャイム検出→Line等で通知まで実装する予定です。